From 9d81114ac296d57535c13bae9df532f81ed7c625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=98=8A?= <948387529@qq.com> Date: Sat, 29 Nov 2025 18:46:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../playedu/api/PlayeduApiApplication.java | 1 + .../api/controller/ExceptionController.java | 6 +- .../backend/admin/LoginController.java | 20 +- .../backend/jc/BookChapterController.java | 172 ++++++++++++- .../backend/jc/JCResourceController.java | 58 ++++- .../backend/jc/TextbookController.java | 53 ++-- .../backend/system/LocalFileController.java | 3 + .../controller/frontend/UserController.java | 180 ++++++++++++-- .../playedu/api/interceptor/WebMvcConfig.java | 16 ++ .../xyz/playedu/jc/domain/JCResource.java | 5 + .../java/xyz/playedu/jc/domain/Textbook.java | 6 +- .../playedu/jc/domain/dto/BookChapterDTO.java | 38 +++ .../jc/domain/dto/TextbookRequestDTO.java | 2 +- .../jc/domain/dto/TextbookUserDTO.java | 58 +++++ .../jc/mapper/BookDepartmentUserMapper.java | 5 + .../jc/service/IBookChapterService.java | 33 +++ .../service/IBookDepartmentUserService.java | 2 + .../playedu/jc/service/ITextbookService.java | 6 + .../jc/service/JCIResourceService.java | 6 +- .../service/impl/BookChapterServiceImpl.java | 232 +++++++++++++++++- .../impl/BookDepartmentUserServiceImpl.java | 25 ++ .../service/impl/JCResourceServiceImpl.java | 89 ++++++- .../jc/service/impl/TextbookServiceImpl.java | 99 +++++++- .../mapper/jc/BookDepartmentUserMapper.xml | 19 +- .../ResourceTranscodeInfoServiceImpl.java | 2 +- 25 files changed, 1053 insertions(+), 83 deletions(-) create mode 100644 app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/BookChapterDTO.java create mode 100644 app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookUserDTO.java diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/PlayeduApiApplication.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/PlayeduApiApplication.java index 7c1210d..e590b9d 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/PlayeduApiApplication.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/PlayeduApiApplication.java @@ -24,6 +24,7 @@ import xyz.playedu.common.config.UniqueNameGeneratorConfig; public class PlayeduApiApplication { public static void main(String[] args) { + System.out.println("start"); // 添加编码设置 System.setProperty("spring.config.encoding", "UTF-8"); ApplicationContext context=SpringApplication.run(PlayeduApiApplication.class, args); diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java index ab6bdea..3a61c9f 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java @@ -44,7 +44,7 @@ public class ExceptionController { @ExceptionHandler(HttpMessageNotReadableException.class) public JsonResponse serviceExceptionHandler(HttpMessageNotReadableException e) { log.error(e.getMessage()); - return JsonResponse.error("参数为空", 406); + return JsonResponse.error("参数为空1", 406); } @ExceptionHandler(MethodArgumentNotValidException.class) @@ -62,13 +62,13 @@ public class ExceptionController { @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public JsonResponse serviceExceptionHandler(HttpRequestMethodNotSupportedException e) { log.error(e.getMessage()); - return JsonResponse.error("请求method错误", 400); + return JsonResponse.error("请求method错误1", 400); } @ExceptionHandler(MethodArgumentTypeMismatchException.class) public JsonResponse serviceExceptionHandler(MethodArgumentTypeMismatchException e) { log.error(e.getMessage()); - return JsonResponse.error("请求错误", 400); + return JsonResponse.error("请求错误1", 400); } @ExceptionHandler(MissingServletRequestParameterException.class) diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/admin/LoginController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/admin/LoginController.java index 9a39e4b..0897b39 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/admin/LoginController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/admin/LoginController.java @@ -64,16 +64,16 @@ public class LoginController { } String limitKey = "admin-login-limit:" + loginRequest.getEmail(); - Long reqCount = rateLimiterService.current(limitKey, 3600L); - if (reqCount > 5 && !playEduConfig.getTesting()) { - Long exp = RedisUtil.ttlWithoutPrefix(limitKey); - String timeMsg = - exp > 60 - ? exp / 60 + MessageUtils.message("分钟") - : exp + MessageUtils.message("秒"); - String msg = MessageUtils.message("您的账号已被锁定,请") + timeMsg + MessageUtils.message("后重试"); - return JsonResponse.error(msg); - } +// Long reqCount = rateLimiterService.current(limitKey, 3600L); +// if (reqCount > 5 && !playEduConfig.getTesting()) { +// Long exp = RedisUtil.ttlWithoutPrefix(limitKey); +// String timeMsg = +// exp > 60 +// ? exp / 60 + MessageUtils.message("分钟") +// : exp + MessageUtils.message("秒"); +// String msg = MessageUtils.message("您的账号已被锁定,请") + timeMsg + MessageUtils.message("后重试"); +// return JsonResponse.error(msg); +// } String password = HelperUtil.MD5(loginRequest.getPassword() + adminUser.getSalt()).toLowerCase(); diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/BookChapterController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/BookChapterController.java index c5333b9..1d8735c 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/BookChapterController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/BookChapterController.java @@ -1,13 +1,40 @@ package xyz.playedu.api.controller.backend.jc; +import jnr.ffi.annotations.In; +import lombok.SneakyThrows; +import org.apache.commons.collections4.MapUtils; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import xyz.playedu.api.avro.DepartmentDestroyAvro; +import xyz.playedu.api.request.backend.DepartmentParentRequest; +import xyz.playedu.api.request.backend.DepartmentRequest; +import xyz.playedu.api.request.backend.DepartmentSortRequest; +import xyz.playedu.common.annotation.BackendPermission; +import xyz.playedu.common.annotation.Log; +import xyz.playedu.common.constant.BPermissionConstant; +import xyz.playedu.common.constant.BusinessTypeConstant; +import xyz.playedu.common.constant.CommonConstant; +import xyz.playedu.common.constant.TopicConstant; +import xyz.playedu.common.context.BCtx; +import xyz.playedu.common.domain.Department; +import xyz.playedu.common.domain.User; +import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.types.JsonResponse; +import xyz.playedu.common.util.DateUtil; +import xyz.playedu.common.util.HelperUtil; +import xyz.playedu.common.util.StringUtil; import xyz.playedu.jc.domain.BookChapter; +import xyz.playedu.jc.domain.dto.BookChapterDTO; import xyz.playedu.jc.domain.dto.ChapterSortDTO; import xyz.playedu.jc.domain.vo.ChapterTreeVO; import xyz.playedu.jc.service.IBookChapterService; +import xyz.playedu.jc.service.IBookDepartmentUserService; +import xyz.playedu.jc.service.ITextbookService; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Optional; @@ -22,6 +49,10 @@ public class BookChapterController { @Autowired private IBookChapterService bookChapterService; + @Autowired + private ITextbookService textbookService; + @Autowired + private IBookDepartmentUserService bookDepartmentUserService; /** 获取某教材的章节平铺列表 */ @GetMapping("/list") @@ -56,11 +87,11 @@ public class BookChapterController { } /** 删除章节(可在 Service 里做子节点/内容校验) */ - @DeleteMapping("/{id}") - public JsonResponse delete(@PathVariable("id") Integer id) { - bookChapterService.removeChapter(id); - return JsonResponse.success(); - } +// @DeleteMapping("/{id}") +// public JsonResponse delete(@PathVariable("id") Integer id) { +// bookChapterService.removeChapter(id); +// return JsonResponse.success(); +// } /** 拖拽排序 / 批量调整层级 */ @PostMapping("/sort") @@ -69,4 +100,135 @@ public class BookChapterController { bookChapterService.sort(bookId, sorts); return JsonResponse.success(); } + + + @GetMapping("/create") + @Log(title = "章节-新建", businessType = BusinessTypeConstant.GET) + public JsonResponse create(@RequestParam("bookId") Integer bookId) { + HashMap data = new HashMap<>(); + // 查询所有的本地部门 + data.put("bookChapter", bookChapterService.groupByParentByBookId(bookId)); + return JsonResponse.data(data); + } + + @PostMapping("/create") + @Log(title = "章节-新建", businessType = BusinessTypeConstant.INSERT) + public JsonResponse store(@RequestBody @Validated BookChapterDTO req) + throws NotFoundException { + // 校验同级是否同名部门 + BookChapter existDepartment = + bookChapterService.chunkByNameAndParentId(req.getName(), req.getParentId()); + if (StringUtil.isNotNull(existDepartment)) { + return JsonResponse.error("章节名称已存在"); + } + BookChapter bookChapter = new BookChapter(); + BeanUtils.copyProperties(req, bookChapter); + bookChapterService.create(bookChapter); + return JsonResponse.success(); + } + + @GetMapping("/{id}") + @Log(title = "章节-编辑", businessType = BusinessTypeConstant.GET) + public JsonResponse edit(@PathVariable Integer id) throws NotFoundException { + BookChapter bookChapter = bookChapterService.findOrFail(id); + return JsonResponse.data(bookChapter); + } + + @PutMapping("/{id}") + @Log(title = "章节-编辑", businessType = BusinessTypeConstant.UPDATE) + public JsonResponse update(@PathVariable Integer id, @RequestBody BookChapterDTO req) + throws NotFoundException { + BookChapter bookChapter = bookChapterService.findOrFail(id); + // 校验同级是否同名部门 + BookChapter existDepartment = + bookChapterService.chunkByNameAndParentId(req.getName(), req.getParentId()); + if (StringUtil.isNotNull(existDepartment) && existDepartment.getId() != id) { + return JsonResponse.error("部门名称已存在"); + } + bookChapterService.update(bookChapter, req.getName(), req.getParentId(), req.getSort()); + return JsonResponse.success(); + } + + + @SneakyThrows + @DeleteMapping("/{id}") + public JsonResponse destroy(@PathVariable Integer id) throws NotFoundException { + BookChapter department = bookChapterService.findOrFail(id); + bookChapterService.destroy(department.getId()); + + + return JsonResponse.success(); + } + + + + @GetMapping("/index") + @Log(title = "章节后台-列表", businessType = BusinessTypeConstant.GET) + public JsonResponse index(@RequestParam HashMap params) { + Integer bookId = MapUtils.getInteger(params, "bookId"); + if (bookId == null && StringUtil.isNull(bookId)) { + return JsonResponse.error("请传入教材id"); + } + HashMap data = new HashMap<>(); + // 只返回树形章节结构 + data.put("chapters", bookChapterService.groupByParentByBookId(bookId)); + return JsonResponse.data(data); +// +// HashMap data = new HashMap<>(); +// data.put("departments", bookChapterService.groupByParentByFromScene(fromScene)); +// +// HashMap depUserCount = new HashMap<>(); +// List allDepartmentList = bookChapterService.allByFromScene(fromScene); +// if (StringUtil.isNotEmpty(allDepartmentList)) { +// for (BookChapter dep : allDepartmentList) { +// List depIds = new ArrayList<>(); +// depIds.add(dep.getId()); +// String parentChain = ""; +// if (StringUtil.isEmpty(dep.getChapterCode())) { +// parentChain = dep.getId() + ""; +// } else { +// parentChain = dep.getChapterCode() + "," + dep.getId(); +// } +// // 获取所有子部门ID +// List childDepartmentList = +// bookChapterService.getChildDepartmentsByParentChain( +// dep.getId(), parentChain); +// if (StringUtil.isNotEmpty(childDepartmentList)) { +// depIds.addAll(childDepartmentList.stream().map(BookChapter::getId).toList()); +// } +//// List departmentUserIds = bookChapterService.getUserIdsByDepIds(depIds); +//// depUserCount.put( +//// dep.getId(), departmentUserIds.stream().distinct().toList().size()); +// } +// } +//// data.put("dep_user_count", depUserCount); +//// data.put("user_total", userService.total()); +// return JsonResponse.data(data); + } + + + @PutMapping("/update/sort") + @Log(title = "章节-更新排序", businessType = BusinessTypeConstant.UPDATE) + public JsonResponse resort(@RequestBody @Validated DepartmentSortRequest req) { + bookChapterService.resetSort(req.getIds()); + return JsonResponse.success(); + } + + @PutMapping("/update/parent") + @Log(title = "章节-更新父级", businessType = BusinessTypeConstant.UPDATE) + public JsonResponse updateParent(@RequestBody @Validated DepartmentParentRequest req) + throws NotFoundException { + bookChapterService.changeParent(req.getId(), req.getParentId(), req.getIds()); + return JsonResponse.success(); + } + + + @GetMapping("/{id}/destroy") + @Log(title = "章节-批量删除", businessType = BusinessTypeConstant.DELETE) + public JsonResponse preDestroy(@PathVariable Integer id) { + HashMap data = new HashMap<>(); + data.put("children", bookChapterService.listByParentId(id)); + return JsonResponse.data(data); + } + } \ No newline at end of file diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/JCResourceController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/JCResourceController.java index a2e98b8..40023f4 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/JCResourceController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/JCResourceController.java @@ -3,12 +3,24 @@ package xyz.playedu.api.controller.backend.jc; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import xyz.playedu.common.config.ServerConfig; +import xyz.playedu.common.constant.CommonConstant; +import xyz.playedu.common.domain.Department; +import xyz.playedu.common.domain.User; +import xyz.playedu.common.domain.UserGroup; import xyz.playedu.common.types.JsonResponse; +import xyz.playedu.common.types.paginate.PaginationResult; +import xyz.playedu.common.util.StringUtil; +import xyz.playedu.common.util.StringUtils; +import xyz.playedu.course.constants.CourseConstant; +import xyz.playedu.jc.domain.BookDepartmentUser; import xyz.playedu.jc.domain.JCResource; +import xyz.playedu.jc.domain.Textbook; import xyz.playedu.jc.domain.dto.ResourcePageRequestDTO; import xyz.playedu.jc.service.JCIResourceService; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; @RestController @RequestMapping("/backend/v1/jc/resource") @@ -16,6 +28,28 @@ public class JCResourceController { @Autowired private JCIResourceService resourceService; + @Autowired + private ServerConfig serverConfig; + + @GetMapping("/index") + public JsonResponse index(@RequestParam HashMap params) { + + /** 调用服务层分页查询方法,Service 层已包含完整的分页信息 */ + PaginationResult result = resourceService.paginate(params); + HashMap data = new HashMap<>(); + data.put("data", result.getData()); + data.put("total", result.getTotal()); + + String url = serverConfig.getUrl(); + + result.getData() + .forEach(item -> item.setAllUrl(url+item.getPath())); + result.getData() + .forEach(item -> item.setUrl(url)); + + /** 直接返回 Service 层的结果 */ + return JsonResponse.data(data); + } @GetMapping("/list") public JsonResponse list(@RequestParam(value = "bookId", required = false) Integer bookId, @@ -50,9 +84,25 @@ public class JCResourceController { } /** 删除资源 */ - @DeleteMapping("/{id}") - public JsonResponse delete(@PathVariable("id") Integer id) { - resourceService.removeById(id); +// @DeleteMapping("/{id}") +// public JsonResponse delete(@PathVariable("id") Integer id) { +// resourceService.removeById(id); +// return JsonResponse.success(); +// } + + + /** 批量删除资源 */ + @DeleteMapping("/delIds") + public JsonResponse delete(@RequestParam(value = "idList", required = false) String idListStr) { + if (StringUtils.isNotBlank(idListStr)) { + List idList = Arrays.stream(idListStr.split(",")) + .map(String::trim) + .filter(str -> !str.isEmpty()) + .map(Integer::parseInt) + .collect(Collectors.toList()); + + resourceService.removeByIds(idList); + } return JsonResponse.success(); } diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/TextbookController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/TextbookController.java index 9ced289..9314fc3 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/TextbookController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/jc/TextbookController.java @@ -1,6 +1,7 @@ package xyz.playedu.api.controller.backend.jc; import cn.hutool.core.util.ObjectUtil; +import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -8,8 +9,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import xyz.playedu.common.annotation.Log; +import xyz.playedu.common.config.ServerConfig; import xyz.playedu.common.constant.BusinessTypeConstant; import xyz.playedu.common.constant.CommonConstant; +import xyz.playedu.common.context.FCtx; import xyz.playedu.common.domain.Department; import xyz.playedu.common.domain.Group; import xyz.playedu.common.domain.User; @@ -17,11 +20,14 @@ import xyz.playedu.common.domain.UserGroup; import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.service.*; import xyz.playedu.common.types.JsonResponse; +import xyz.playedu.common.types.mapper.UserCourseHourRecordCourseCountMapper; import xyz.playedu.common.types.paginate.PaginationResult; import xyz.playedu.common.util.StringUtil; import xyz.playedu.course.constants.CourseConstant; import xyz.playedu.course.domain.Course; import xyz.playedu.course.domain.CourseDepartmentUser; +import xyz.playedu.course.domain.CourseHour; +import xyz.playedu.course.domain.UserCourseRecord; import xyz.playedu.jc.domain.BookDepartmentUser; import xyz.playedu.jc.domain.JCResource; import xyz.playedu.jc.domain.Textbook; @@ -31,10 +37,7 @@ import xyz.playedu.jc.service.ITextbookService; import xyz.playedu.jc.service.JCIResourceService; import xyz.playedu.knowledge.domain.KnowledgeMessages; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -58,7 +61,8 @@ public class TextbookController { @Autowired private UserService userService; @Autowired private GroupService groupService; - + @Autowired + private ServerConfig serverConfig; @GetMapping("/index") public JsonResponse index(@RequestParam HashMap params) { @@ -68,24 +72,16 @@ public class TextbookController { data.put("data", result.getData()); data.put("total", result.getTotal()); - // 课程封面资源ID - List rids = new ArrayList<>(); - rids.addAll(result.getData().stream().map(Textbook::getThumb).toList()); + String url = serverConfig.getUrl(); + + result.getData() + .forEach(item -> item.setAllUrl(url+item.getThumb())); + result.getData() + .forEach(item -> item.setUrl(url)); + + List bookIds = result.getData().stream().map(Textbook::getId).toList(); -// data.put("course_category_ids", courseService.getCategoryIdsGroup(courseIds)); -// data.put("categories", categoryService.id2name()); -// data.put("departments", departmentService.id2name()); - -// Map courseIdRecordCountMap = new HashMap<>(); -// doGetRecords(courseIds) -// .forEach( -// (key, value) -> { -// courseIdRecordCountMap.put(key, value.size()); -// }); -// data.put("records", courseIdRecordCountMap); - // 获取签名url - data.put("resource_url", jciResourceService.chunksPreSignUrlByIds(rids)); // 指派范围 Map book_user_count = new HashMap<>(); @@ -203,13 +199,17 @@ public class TextbookController { public JsonResponse edit(@PathVariable(name = "id") Integer id) throws NotFoundException { Textbook textbook = textbookService.findOrFail(id); + String url = serverConfig.getUrl(); + textbook.setAllUrl(url + textbook.getThumb()); + textbook.setUrl(url); + HashMap data = new HashMap<>(); data.put("textbook", textbook); - List rids = new ArrayList<>(); - rids.add(textbook.getThumb()); - // 获取签名url - data.put("resource_url", jciResourceService.chunksPreSignUrlByIds(rids)); +// List rids = new ArrayList<>(); +// rids.add(textbook.getThumb()); +// 获取签名url +// data.put("resource_url", jciResourceService.chunksPreSignUrlByIds(rids)); // 指派范围 List courseDepartmentUserList = @@ -347,4 +347,7 @@ public class TextbookController { textbookService.updateById(textbook); return JsonResponse.success(); } + + + } \ No newline at end of file diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/system/LocalFileController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/system/LocalFileController.java index 5fbaf60..bbbf5a9 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/system/LocalFileController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/backend/system/LocalFileController.java @@ -45,12 +45,15 @@ public class LocalFileController { // 上传并返回新文件名称 String fileName = FileUploadUtils.upload(filePath, file); try { + long size = file.getSize(); // 这里拿到文件大小,单位 bytes + String url = serverConfig.getUrl() + fileName; JSONObject ajax = new JSONObject(); ajax.put("url", url); ajax.put("path", fileName); ajax.put("newFileName", FileUploadUtils.getName(fileName)); ajax.put("originalFilename", file.getOriginalFilename()); + ajax.put("size", size); return JsonResponse.data(ajax); } catch (Exception e) { return JsonResponse.error(e.getMessage()); diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/UserController.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/UserController.java index 7b43c89..d5e5645 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/UserController.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/UserController.java @@ -5,9 +5,11 @@ package xyz.playedu.api.controller.frontend; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; + import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; + import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.MapUtils; @@ -17,12 +19,15 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import xyz.playedu.api.request.frontend.ChangePasswordRequest; +import xyz.playedu.common.annotation.Log; import xyz.playedu.common.caches.CurrentDepIdCache; import xyz.playedu.common.caches.LoginCreditCache; +import xyz.playedu.common.constant.BusinessTypeConstant; import xyz.playedu.common.constant.CommonConstant; import xyz.playedu.common.constant.FrontendConstant; import xyz.playedu.common.context.FCtx; import xyz.playedu.common.domain.*; +import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.exception.ServiceException; import xyz.playedu.common.service.*; import xyz.playedu.common.types.JsonResponse; @@ -40,6 +45,10 @@ import xyz.playedu.exam.service.ExamTaskDepartmentUserService; import xyz.playedu.exam.service.ExamTaskUserService; import xyz.playedu.exam.service.StudyTaskDepartmentUserService; import xyz.playedu.exam.service.StudyTaskUserService; +import xyz.playedu.jc.domain.Textbook; +import xyz.playedu.jc.domain.dto.TextbookUserDTO; +import xyz.playedu.jc.service.IBookChapterService; +import xyz.playedu.jc.service.ITextbookService; import xyz.playedu.resource.domain.Resource; import xyz.playedu.resource.service.ResourceService; import xyz.playedu.resource.service.UploadService; @@ -49,47 +58,68 @@ import xyz.playedu.resource.service.UploadService; @Slf4j public class UserController { - @Autowired private UserService userService; + @Autowired + private UserService userService; - @Autowired private DepartmentService departmentService; + @Autowired + private DepartmentService departmentService; - @Autowired private CourseService courseService; + @Autowired + private CourseService courseService; - @Autowired private CourseHourService hourService; + @Autowired + private CourseHourService hourService; - @Autowired private UserCourseRecordService userCourseRecordService; + @Autowired + private UserCourseRecordService userCourseRecordService; - @Autowired private UserCourseHourRecordService userCourseHourRecordService; + @Autowired + private UserCourseHourRecordService userCourseHourRecordService; - @Autowired private UserLearnDurationStatsService userLearnDurationStatsService; + @Autowired + private UserLearnDurationStatsService userLearnDurationStatsService; - @Autowired private UploadService uploadService; + @Autowired + private UploadService uploadService; - @Autowired private CertUserService certUserService; + @Autowired + private CertUserService certUserService; - @Autowired private CertService certService; + @Autowired + private CertService certService; - @Autowired private ExamTaskUserService examTaskUserService; + @Autowired + private ExamTaskUserService examTaskUserService; - @Autowired private StudyTaskUserService studyTaskUserService; + @Autowired + private StudyTaskUserService studyTaskUserService; - @Autowired private ResourceService resourceService; + @Autowired + private ResourceService resourceService; - @Autowired private UserUploadImageLogService userUploadImageLogService; + @Autowired + private UserUploadImageLogService userUploadImageLogService; - @Autowired private AppConfigService appConfigService; + @Autowired + private AppConfigService appConfigService; - @Autowired private CurrentDepIdCache currentDepIdCache; + @Autowired + private CurrentDepIdCache currentDepIdCache; - @Autowired private ExamTaskDepartmentUserService examTaskDepartmentUserService; + @Autowired + private ExamTaskDepartmentUserService examTaskDepartmentUserService; - @Autowired private StudyTaskDepartmentUserService studyTaskDepartmentUserService; + @Autowired + private StudyTaskDepartmentUserService studyTaskDepartmentUserService; - @Autowired private CreditRuleService creditRuleService; + @Autowired + private CreditRuleService creditRuleService; - @Autowired private UserCreditDetailService userCreditDetailService; + @Autowired + private UserCreditDetailService userCreditDetailService; - @Autowired private LoginCreditCache loginCreditCache; + @Autowired + private LoginCreditCache loginCreditCache; @GetMapping("/detail") public JsonResponse detail() { @@ -613,4 +643,112 @@ public class UserController { } return JsonResponse.data(data); } + + @Autowired + private ITextbookService textbookService; + + @GetMapping("/userByTextBook") + public JsonResponse userByTextBook(@RequestParam HashMap params) throws NotFoundException { + Integer depId = MapUtils.getInteger(params, "dep_id"); + if (depId == null || depId == 0) { + return JsonResponse.error("部门为空"); + } + +// Integer categoryId = MapUtils.getInteger(params, "category_id"); + + String name = MapUtils.getString(params, "name"); + String publishTime = MapUtils.getString(params, "publishTime"); + String major = MapUtils.getString(params, "major"); + + List userJoinDepIds = userService.getDepIdsByUserId(FCtx.getId()); + if (userJoinDepIds == null) { + return JsonResponse.error("当前学员未加入任何部门"); + } + if (!userJoinDepIds.contains(depId)) { + return JsonResponse.error("当前学员未加入所选择部门"); + } + + HashMap data = new HashMap<>(); + data.put("learn_course_records", new HashMap<>()); + + // 获取所有部门ID + List depIds = new ArrayList<>(); + depIds.add(depId); + Department department = departmentService.findOrFail(depId); + String parentChain = department.getParentChain(); + if (StringUtil.isNotEmpty(parentChain)) { + List parentChainList = + Arrays.stream(parentChain.split(",")).map(Integer::parseInt).toList(); + if (StringUtil.isNotEmpty(parentChainList)) { + depIds.addAll(parentChainList); + } + } + List userIds = new ArrayList<>(); + userIds.add(FCtx.getId()); + TextbookUserDTO textbookUserDTO = new TextbookUserDTO(); + textbookUserDTO.setUserIds(userIds); + textbookUserDTO.setDepIds(depIds); + textbookUserDTO.setPublishTime(publishTime); + textbookUserDTO.setMajor(major); + textbookUserDTO.setName(name); + // -------- 读取当前学员可以参加的课程 ---------- + List courses = new ArrayList<>(); + // 读取部门课 + List depCourses = + textbookService.getDepCoursesAndShow( + textbookUserDTO); + + // 汇总到一个list中 + if (depCourses != null && !depCourses.isEmpty()) { + courses.addAll(depCourses); + } + // 对结果进行去重、排序->按照id去重、排序时间倒序 + if (!courses.isEmpty()) { + courses = + courses.stream() + .collect( + Collectors.collectingAndThen( + Collectors.toCollection( + () -> + new TreeSet<>( + Comparator.comparing( + Textbook::getId))), + ArrayList::new)) + .stream() + .sorted( + Comparator.comparing( + (Textbook c) -> + c.getCreateTime() != null + ? c.getPublishTime() + : new Date(0)) + .reversed()) + .toList(); + } + + data.put("textbook", courses); + +// List courseIds = courses.stream().map(Textbook::getId).toList(); + + + return JsonResponse.data(data); + } + @Autowired + private IBookChapterService bookChapterService; + @GetMapping("/index") + @Log(title = "章节后台-列表", businessType = BusinessTypeConstant.GET) + public JsonResponse index(@RequestParam HashMap params) { + Integer bookId = MapUtils.getInteger(params, "bookId"); + if (bookId == null && StringUtil.isNull(bookId)) { + return JsonResponse.error("请传入教材id"); + } + HashMap data = new HashMap<>(); + // 只返回树形章节结构 + data.put("chapters", bookChapterService.groupByParentByBookId(bookId)); + return JsonResponse.data(data); + + } + + + + } diff --git a/app/api/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java b/app/api/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java index b84e201..2bf7ca8 100644 --- a/app/api/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java +++ b/app/api/playedu-api/src/main/java/xyz/playedu/api/interceptor/WebMvcConfig.java @@ -9,7 +9,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import xyz.playedu.common.config.PlatformConfig; +import xyz.playedu.common.util.FileUploadUtils; @Configuration @Slf4j @@ -36,4 +39,17 @@ public class WebMvcConfig implements WebMvcConfigurer { .allowedHeaders("*") .maxAge(1_296_000); } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // profile = platform.config.profile,比如:/data/platform + String profile = PlatformConfig.getProfile(); + if (!profile.endsWith("/")) { + profile = profile + "/"; + } + + // /profile/** 访问的是磁盘上的 profile 目录 + registry.addResourceHandler(FileUploadUtils.RESOURCE_PREFIX + "/**") + .addResourceLocations("file:" + profile); + } } diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/JCResource.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/JCResource.java index 1db3b6e..ca6e3ac 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/JCResource.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/JCResource.java @@ -75,4 +75,9 @@ public class JCResource { @TableField("tenant_id") private String tenantId; + + @TableField(exist = false) + private String url; + @TableField(exist = false) + private String allUrl; } diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/Textbook.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/Textbook.java index e6c8719..4dfd672 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/Textbook.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/Textbook.java @@ -26,7 +26,7 @@ public class Textbook extends TenantBaseDO { /** 封面地址 */ @TableField("thumb") - private Integer thumb; + private String thumb; /** 简介 */ @TableField("short_desc") @@ -54,5 +54,9 @@ public class Textbook extends TenantBaseDO { /** 发布时间 */ @TableField("publish_time") private Date publishTime; + @TableField(exist = false) + private String url; + @TableField(exist = false) + private String allUrl; } diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/BookChapterDTO.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/BookChapterDTO.java new file mode 100644 index 0000000..316f4c8 --- /dev/null +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/BookChapterDTO.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 杭州白书科技有限公司 + */ +package xyz.playedu.jc.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @Author 杭州白书科技有限公司 + * + * @create 2023/2/19 10:42 + */ +@Data +public class BookChapterDTO implements Serializable { + @Serial private static final long serialVersionUID = 1L; + + @NotBlank(message = "name参数为空") + @Length(min = 1, max = 64, message = "名称长度在1-64个字符之间") + private String name; + + @JsonProperty("parentId") + @NotNull(message = "parentId参数为空") + private Integer parentId; + + @JsonProperty("bookId") + @NotNull(message = "bookId参数为空") + private Integer bookId; + + @NotNull(message = "sort参数为空") + private Integer sort; +} diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookRequestDTO.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookRequestDTO.java index 567fa73..8b9f1b9 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookRequestDTO.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookRequestDTO.java @@ -26,7 +26,7 @@ public class TextbookRequestDTO { /** 封面地址 */ @TableField("thumb") - private Integer thumb; + private String thumb; /** 简介 */ @TableField("short_desc") diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookUserDTO.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookUserDTO.java new file mode 100644 index 0000000..e398e03 --- /dev/null +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/domain/dto/TextbookUserDTO.java @@ -0,0 +1,58 @@ +package xyz.playedu.jc.domain.dto; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * + * 对应表: + */ +@Data +public class TextbookUserDTO { + + +// /** 教材名称 */ +// @TableField("title") +// private String title; +// +// /** 封面地址 */ +// @TableField("thumb") +// private String thumb; + + /** 简介 */ +// @TableField("short_desc") +// private String shortDesc; + + /** 学科专业信息 */ + @TableField("major") + private String major; + +// /** 作者 */ +// @TableField("author") +// private String author; +// +// /** ISBN 或教材编号 */ +// @TableField("isbn") +// private String isbn; + + + /** 出版社 */ +// @TableField("publish_unit") +// private String publishUnit; + + /** 发布时间 */ + private String publishTime; + + private String name; + + private List depIds; + + private List userIds; + +} \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/mapper/BookDepartmentUserMapper.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/mapper/BookDepartmentUserMapper.java index e07140c..8b22a3c 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/mapper/BookDepartmentUserMapper.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/mapper/BookDepartmentUserMapper.java @@ -1,7 +1,12 @@ package xyz.playedu.jc.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import xyz.playedu.course.domain.CourseDepartmentUser; import xyz.playedu.jc.domain.BookDepartmentUser; +import java.util.List; + public interface BookDepartmentUserMapper extends BaseMapper { + List chunksByDepIdsOrUserIdsOrGroupIds( + List depIds, List userIds, List groupIds); } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookChapterService.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookChapterService.java index 036539e..45a4562 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookChapterService.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookChapterService.java @@ -1,11 +1,14 @@ package xyz.playedu.jc.service; import com.baomidou.mybatisplus.extension.service.IService; +import xyz.playedu.common.domain.Department; +import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.jc.domain.BookChapter; import xyz.playedu.jc.domain.dto.ChapterSortDTO; import xyz.playedu.jc.domain.vo.ChapterTreeVO; import java.util.List; +import java.util.Map; /** * 教材章节 Service @@ -28,4 +31,34 @@ public interface IBookChapterService extends IService { /** 删除章节时做子节点/内容校验(需要的话) */ void removeChapter(Integer id); + +// List getUserIdsByDepIds(List depIds); + + + Map> groupByParentByBookId(Integer bookId); + + List allByFromScene(Integer fromScene); + List getChildDepartmentsByParentChain(Integer parentId, String parentChain); + void destroy(Integer id) throws NotFoundException; + + List listByParentId(Integer id); + + + void changeParent(Integer id, Integer parentId, List ids) throws NotFoundException; + + void resetSort(List ids); + + BookChapter findOrFail(Integer id) throws NotFoundException; + + String childrenParentChain(BookChapter bookChapter); + + void update(BookChapter bookChapter, String name, Integer parentId, Integer sort) + throws NotFoundException; + + BookChapter chunkByNameAndParentId(String name, Integer parentId); + + BookChapter create(BookChapter bookChapter) + throws NotFoundException; + + String compParentChain(Integer parentId) throws NotFoundException; } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookDepartmentUserService.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookDepartmentUserService.java index 9ca0091..cc7b1bd 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookDepartmentUserService.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/IBookDepartmentUserService.java @@ -12,4 +12,6 @@ public interface IBookDepartmentUserService extends IService List chunksByBookIds(List bookIds); List chunksByCourseId(Integer courseId); + + List getCourseIdsByDepIdsOrUserIds(List depIds, List userIds); } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/ITextbookService.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/ITextbookService.java index 54f337e..4314e9c 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/ITextbookService.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/ITextbookService.java @@ -3,10 +3,13 @@ package xyz.playedu.jc.service; import com.baomidou.mybatisplus.extension.service.IService; import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.types.paginate.PaginationResult; +import xyz.playedu.course.domain.Course; import xyz.playedu.jc.domain.JCResource; import xyz.playedu.jc.domain.Textbook; +import xyz.playedu.jc.domain.dto.TextbookUserDTO; import java.util.HashMap; +import java.util.List; /** * 教材 Service @@ -17,4 +20,7 @@ public interface ITextbookService extends IService { Textbook findOrFail(Integer id) throws NotFoundException; + List getDepCoursesAndShow( + TextbookUserDTO textbookUserDTO); + } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/JCIResourceService.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/JCIResourceService.java index ff83fb5..d9f244a 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/JCIResourceService.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/JCIResourceService.java @@ -2,13 +2,17 @@ package xyz.playedu.jc.service; import com.baomidou.mybatisplus.extension.service.IService; import xyz.playedu.common.exception.NotFoundException; +import xyz.playedu.common.types.paginate.PaginationResult; import xyz.playedu.course.domain.Course; import xyz.playedu.jc.domain.JCResource; +import xyz.playedu.jc.domain.Textbook; +import java.util.HashMap; import java.util.List; import java.util.Map; public interface JCIResourceService extends IService { - Map chunksPreSignUrlByIds(List ids); + Map chunksPreSignUrlByIds(List ids); + PaginationResult paginate(HashMap params); } diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookChapterServiceImpl.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookChapterServiceImpl.java index 4578119..6f3d4ff 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookChapterServiceImpl.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookChapterServiceImpl.java @@ -3,16 +3,17 @@ package xyz.playedu.jc.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; +import xyz.playedu.common.domain.Department; +import xyz.playedu.common.exception.NotFoundException; +import xyz.playedu.common.util.StringUtil; import xyz.playedu.jc.domain.BookChapter; import xyz.playedu.jc.domain.dto.ChapterSortDTO; import xyz.playedu.jc.domain.vo.ChapterTreeVO; import xyz.playedu.jc.mapper.BookChapterMapper; import xyz.playedu.jc.service.IBookChapterService; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; /** * 教材章节 Service 实现 @@ -95,4 +96,227 @@ public class BookChapterServiceImpl //todo 校验是否有子节点 / 内容 removeById(id); } + @Override + public Map> groupByParentByBookId(Integer bookId) { + return list(query().getWrapper().eq("book_id", bookId).orderByAsc("sort")) + .stream() + .collect(Collectors.groupingBy(BookChapter::getParentId)); + +// return list( +// query() +// .getWrapper() +// .eq(BookChapter::getBookId, bookId) // ✅ 插入条件 +// .orderByAsc(BookChapter::getParentId) +// ) +// .stream() +// .collect(Collectors.groupingBy(BookChapter::getParentId)); + } + + + +// @Override +// public List getUserIdsByDepIds(List depIds) { +// if (StringUtil.isEmpty(depIds)) { +// return new ArrayList<>(); +// } +// return list(query().getWrapper().in("dep_id", depIds)).stream() +// .map(UserDepartment::getUserId) +// .toList(); +// } + + @Override + public List allByFromScene(Integer fromScene) { + if (StringUtil.isNull(fromScene)) { + return list(query().getWrapper().orderByAsc("sort")); + } else { + return list(query().getWrapper().eq("from_scene", fromScene).orderByAsc("sort")); + } + } + + @Override + public List getChildDepartmentsByParentChain(Integer parentId, String parentChain) { + if (StringUtil.isEmpty(parentChain)) { + return new ArrayList<>(); + } + return list( + query().getWrapper() + .eq("parent_id", parentId) + .or() + .likeRight("parent_chain", parentChain + ",")); + } + + @Override + public void destroy(Integer id) throws NotFoundException { + BookChapter bookChapter = getById(id); + if (bookChapter != null) { + updateParentChain(bookChapter.getChapterCode(), childrenParentChain(bookChapter)); + removeById(bookChapter.getId()); + } + } + + + @Override + public List listByParentId(Integer id) { + return list(query().getWrapper().eq("parent_id", id).orderByAsc("sort")); + } + + @Override + public void changeParent(Integer id, Integer parentId, List ids) + throws NotFoundException { + BookChapter bookChapter = findOrFail(id); + update(bookChapter, bookChapter.getName(), parentId, bookChapter.getSort()); + // 重置排序 + resetSort(ids); + } + + @Override + public void resetSort(List ids) { + if (ids == null || ids.isEmpty()) { + return; + } + List departments = new ArrayList<>(); + int sortVal = 0; + for (Integer idItem : ids) { + Integer finalSortVal = ++sortVal; + departments.add( + new BookChapter() { + { + setId(idItem); + setSort(finalSortVal); + } + }); + } + updateBatchById(departments); + } + + + @Override + public void update(BookChapter bookChapter, String name, Integer parentId, Integer sort) + throws NotFoundException { + // 计算该部门作为其它子部门的parentChain值 + String childrenChainPrefix = childrenParentChain(bookChapter); + + BookChapter data = new BookChapter(); + data.setId(bookChapter.getId()); + data.setName(name); +// data.setFromScene(bookChapter.getFromScene()); + + if (!bookChapter.getParentId().equals(parentId)) { + data.setParentId(parentId); + if (parentId.equals(0)) { // 重置一级部门 + data.setChapterCode(""); + } else { + BookChapter parentBookChapter = findOrFail(parentId); + data.setChapterCode(childrenParentChain(parentBookChapter)); + } + } + if (!bookChapter.getSort().equals(sort)) { // 更换部门排序值 + data.setSort(sort); + } + + // 提交更换 + updateById(data); + + bookChapter = getById(bookChapter.getId()); + updateParentChain(childrenParentChain(bookChapter), childrenChainPrefix); + } + + + private void updateParentChain(String newChildrenPC, String oldChildrenPC) { + List children = + list(query().getWrapper().like("chapter_code", oldChildrenPC + "%")); + if (children.isEmpty()) { + return; + } + + ArrayList updateRows = new ArrayList<>(); + for (BookChapter tmpDepartment : children) { + BookChapter tmpUpdateDepartment = new BookChapter(); + tmpUpdateDepartment.setId(tmpDepartment.getId()); + + // parentChain计算 + String pc = newChildrenPC; + if (!tmpDepartment.getChapterCode().equals(oldChildrenPC)) { + pc = + tmpDepartment + .getChapterCode() + .replaceFirst( + oldChildrenPC + ",", + newChildrenPC.isEmpty() + ? newChildrenPC + : newChildrenPC + ','); + } + tmpUpdateDepartment.setChapterCode(pc); + + // parentId计算 + int parentId = 0; + if (pc != null && !pc.isEmpty()) { + String[] parentIds = pc.split(","); + parentId = Integer.parseInt(parentIds[parentIds.length - 1]); + } + tmpUpdateDepartment.setParentId(parentId); + + updateRows.add(tmpUpdateDepartment); + } + updateBatchById(updateRows); + } + + + /** + * 章节id查询 + * @param id + * @return + * @throws NotFoundException + */ + @Override + public BookChapter findOrFail(Integer id) throws NotFoundException { + BookChapter bookChapter = getById(id); + if (bookChapter == null) { + throw new NotFoundException("部门不存在"); + } + return bookChapter; + } + + + @Override + public String childrenParentChain(BookChapter bookChapter) { + String prefix = bookChapter.getId() + ""; + if (bookChapter.getChapterCode() != null && !bookChapter.getChapterCode().isEmpty()) { + prefix = bookChapter.getChapterCode() + "," + prefix; + } + return prefix; + } + + @Override + public BookChapter chunkByNameAndParentId(String name, Integer parentId) { + return getOne(query().getWrapper().eq("name", name).eq("parent_id", parentId)); + } + + @Override + public BookChapter create(BookChapter bookChapter) + throws NotFoundException { + String parentChain = ""; + if (bookChapter.getParentId() != 0) { + parentChain = compParentChain(bookChapter.getParentId()); + } + bookChapter.setChapterCode(parentChain); + save(bookChapter); + + return bookChapter; + } + + + @Override + public String compParentChain(Integer parentId) throws NotFoundException { + String parentChain = ""; + if (parentId != 0) { + BookChapter bookChapter = getById(parentId); + if (bookChapter == null) { + throw new NotFoundException("父级部门不存在"); + } + String pc = bookChapter.getChapterCode(); + parentChain = pc == null || pc.isEmpty() ? parentId + "" : pc + "," + parentId; + } + return parentChain; + } } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookDepartmentUserServiceImpl.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookDepartmentUserServiceImpl.java index ff7f235..f934535 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookDepartmentUserServiceImpl.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/BookDepartmentUserServiceImpl.java @@ -1,18 +1,25 @@ package xyz.playedu.jc.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import xyz.playedu.common.domain.UserGroup; +import xyz.playedu.common.service.UserGroupService; +import xyz.playedu.common.util.StringUtil; import xyz.playedu.course.domain.CourseDepartmentUser; import xyz.playedu.jc.domain.BookDepartmentUser; import xyz.playedu.jc.mapper.BookDepartmentUserMapper; import xyz.playedu.jc.service.IBookDepartmentUserService; +import java.util.ArrayList; import java.util.List; @Service public class BookDepartmentUserServiceImpl extends ServiceImpl implements IBookDepartmentUserService { + @Autowired + private UserGroupService userGroupService; @Override public void removeByBookId(Integer bookId) { @@ -29,4 +36,22 @@ public class BookDepartmentUserServiceImpl return list(query().getWrapper().eq("book_id", bookId)); } + @Override + public List getCourseIdsByDepIdsOrUserIds( + List depIds, List userIds) { + + List groupIds = new ArrayList<>(); + List userGroupList = userGroupService.chunksByUserIds(userIds); + if (StringUtil.isNotEmpty(userGroupList)) { + groupIds.addAll(userGroupList.stream().map(UserGroup::getGroupId).toList()); + } + List departmentUserList = + getBaseMapper().chunksByDepIdsOrUserIdsOrGroupIds(depIds, userIds, groupIds); + if (StringUtil.isEmpty(departmentUserList)) { + return new ArrayList<>(); + } + + return departmentUserList.stream().map(BookDepartmentUser::getBookId).toList(); + } + } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/JCResourceServiceImpl.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/JCResourceServiceImpl.java index 7f1f4f2..ef7f0d6 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/JCResourceServiceImpl.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/JCResourceServiceImpl.java @@ -1,22 +1,31 @@ package xyz.playedu.jc.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.MapUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.service.AppConfigService; +import xyz.playedu.common.types.paginate.PaginationResult; import xyz.playedu.common.util.S3Util; import xyz.playedu.common.util.StringUtil; import xyz.playedu.course.domain.Course; import xyz.playedu.jc.domain.JCResource; +import xyz.playedu.jc.domain.Textbook; import xyz.playedu.jc.mapper.JCResourceMapper; import xyz.playedu.jc.service.JCIResourceService; import xyz.playedu.resource.domain.Resource; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +@Slf4j @Service public class JCResourceServiceImpl extends ServiceImpl @@ -24,9 +33,85 @@ public class JCResourceServiceImpl @Autowired private AppConfigService appConfigService; - @Override - public Map chunksPreSignUrlByIds(List ids) { + public PaginationResult paginate(HashMap params) { + try { + /** 获取分页参数,默认第1页,每页10条 */ + Integer page = MapUtils.getInteger(params, "page", 1); + Integer size = MapUtils.getInteger(params, "size", 10); + /** 创建分页对象 */ + Page pageParam = new Page<>(page, size); + + /** 创建 Lambda 条件构造器,用于构建类型安全的查询条件 */ + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + /** 固定条件:只查询未删除的记录(km_is_del = false) */ +// queryWrapper.eq(Textbook::getKmIsDel, false); + + /** 动态添加查询条件:资源类型 */ + if (MapUtils.getString(params, "type") != null && !MapUtils.getString(params, "type").isEmpty()) { + queryWrapper.eq(JCResource::getType, MapUtils.getString(params, "type")); + } + + /** 添加排序条件:按创建时间降序排列 默认时间降序*/ + if (MapUtils.getString(params, "sortOrder") != null + && !MapUtils.getString(params, "sortOrder").isEmpty() + && MapUtils.getString(params, "sortFiled") != null + && !MapUtils.getString(params, "sortFiled").isEmpty() + ) { + String sortOrder = MapUtils.getString(params, "sortOrder"); + String sortFiled = MapUtils.getString(params, "sortFiled"); + if ("ascend".equals(sortOrder)){ + if ("name".equals(sortFiled)) { + queryWrapper.orderByAsc(JCResource::getName); + }else if ("size".equals(sortFiled)){ + queryWrapper.orderByAsc(JCResource::getSize); + }else { + queryWrapper.orderByAsc(JCResource::getCreateTime); + } + }else { + if ("name".equals(sortFiled)) { + queryWrapper.orderByDesc(JCResource::getName); + }else if ("size".equals(sortFiled)){ + queryWrapper.orderByDesc(JCResource::getSize); + }else { + queryWrapper.orderByDesc(JCResource::getCreateTime); + } + } + }else { + queryWrapper.orderByDesc(JCResource::getCreateTime); + } + + /** 执行分页查询 */ + IPage pageResult = this.page(pageParam, queryWrapper); + + /** 计算总页数 */ + Long total = pageResult.getTotal(); + Long pages = (total + size - 1) / size; // 向上取整 + + /** 构建返回结果,包含完整的分页信息 */ + PaginationResult result = new PaginationResult<>(); + result.setData(pageResult.getRecords()); + result.setTotal(total); + result.setCurrent(page); // 当前页码 + result.setSize(size); // 每页大小 + result.setPages(pages); // 总页数 + + return result; + } catch (Exception e) { + log.error("分页查询消息失败,参数:{}", params, e); + /** 返回空结果 */ + PaginationResult emptyResult = new PaginationResult<>(); + emptyResult.setData(new ArrayList<>()); + emptyResult.setTotal(0L); + emptyResult.setCurrent(MapUtils.getInteger(params, "page", 1)); + emptyResult.setSize(MapUtils.getInteger(params, "size", 10)); + emptyResult.setPages(0L); + return emptyResult; + } + } + @Override + public Map chunksPreSignUrlByIds(List ids) { S3Util s3Util = new S3Util(appConfigService.getS3Config()); Map preSignUrlMap = new HashMap<>(); diff --git a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/TextbookServiceImpl.java b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/TextbookServiceImpl.java index 2315fa3..ca733ee 100644 --- a/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/TextbookServiceImpl.java +++ b/app/api/playedu-course/src/main/java/xyz/playedu/jc/service/impl/TextbookServiceImpl.java @@ -2,21 +2,32 @@ package xyz.playedu.jc.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.MapUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import xyz.playedu.common.config.ServerConfig; import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.types.paginate.PaginationResult; +import xyz.playedu.common.util.StringUtil; +import xyz.playedu.course.domain.Course; import xyz.playedu.jc.domain.JCResource; import xyz.playedu.jc.domain.Textbook; +import xyz.playedu.jc.domain.dto.TextbookUserDTO; import xyz.playedu.jc.mapper.TextbookMapper; +import xyz.playedu.jc.service.IBookDepartmentUserService; import xyz.playedu.jc.service.ITextbookService; import xyz.playedu.knowledge.domain.KnowledgeMessages; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; /** * 教材 Service 实现 @@ -48,11 +59,18 @@ public class TextbookServiceImpl LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); /** 固定条件:只查询未删除的记录(km_is_del = false) */ -// queryWrapper.eq(Textbook::getKmIsDel, false); + // queryWrapper.eq(Textbook::getKmIsDel, false); - /** 动态添加查询条件:会话ID */ - if (MapUtils.getString(params, "title") != null && !MapUtils.getString(params, "title").isEmpty()) { - queryWrapper.eq(Textbook::getTitle, MapUtils.getString(params, "title")); + /** 动态添加查询条件:关键词 */ + String title = MapUtils.getString(params, "title"); + + // 动态添加模糊查询条件:name / author / . + if (title != null && !title.isEmpty()) { + queryWrapper.and(w -> w + .like(Textbook::getTitle, title) // 书名模糊 + .or().like(Textbook::getAuthor, title) // 作者模糊 + .or().like(Textbook::getMajor, title) // 专业模糊 + ); } @@ -96,4 +114,77 @@ public class TextbookServiceImpl } return textbook; } + @Autowired + private ServerConfig serverConfig; + @Autowired + private IBookDepartmentUserService bookDepartmentUserService; + @Override + public List getDepCoursesAndShow( + TextbookUserDTO textbookUserDTO) { + if (StringUtil.isEmpty(textbookUserDTO.getDepIds())) { + return new ArrayList<>(); + } + +// List res = new ArrayList<>(); + + List courseIds = + bookDepartmentUserService.getCourseIdsByDepIdsOrUserIds(textbookUserDTO.getDepIds(), textbookUserDTO.getUserIds()); + if (StringUtil.isEmpty(courseIds)) { + return new ArrayList<>(); + } +// if (categoryId != null && categoryId > 0) { +// // 获取所有子类 +// List allCategoryIdsList = +// categoryService.getChildCategoryIdsByParentId(categoryId + ""); +// List tmpCourseIds = +// courseCategoryService.getCourseIdsByCategoryIds(allCategoryIdsList); +// if (StringUtil.isEmpty(tmpCourseIds)) { +// return new ArrayList<>(); +// } +// courseIds = courseIds.stream().filter(tmpCourseIds::contains).toList(); +// if (StringUtil.isEmpty(courseIds)) { +// return new ArrayList<>(); +// } +// } + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + +// 课程范围 + queryWrapper.in(Textbook::getId, courseIds); + +// 关键字查询:书名 / 作者 / 专业 + String keyword = textbookUserDTO.getName(); + if (keyword != null && !keyword.isEmpty()) { + queryWrapper.and(w -> w + .like(Textbook::getTitle, keyword) + .or().like(Textbook::getAuthor, keyword) + .or().like(Textbook::getMajor, keyword) + ); + } + +// 出版年份查询(只传年份,比如 "2024") + String publishYearStr = textbookUserDTO.getPublishTime(); + if (publishYearStr != null && !publishYearStr.isEmpty()) { + int year = Integer.parseInt(publishYearStr); + LocalDateTime start = LocalDateTime.of(year, 1, 1, 0, 0, 0); + LocalDateTime end = start.plusYears(1); + + queryWrapper.ge(Textbook::getPublishTime, start) + .lt(Textbook::getPublishTime, end); + } + +// 专业单独查询(如果是专门挑专业) + String major = textbookUserDTO.getMajor(); + if (major != null && !major.isEmpty()) { + queryWrapper.like(Textbook::getMajor, major); + } + + List res = list(queryWrapper); + + for (Textbook re : res) { + re.setAllUrl(serverConfig.getUrl() + re.getThumb()); + re.setUrl(serverConfig.getUrl()); + } + return res; + + } } \ No newline at end of file diff --git a/app/api/playedu-course/src/main/resources/mapper/jc/BookDepartmentUserMapper.xml b/app/api/playedu-course/src/main/resources/mapper/jc/BookDepartmentUserMapper.xml index f54e7ab..fa7122d 100644 --- a/app/api/playedu-course/src/main/resources/mapper/jc/BookDepartmentUserMapper.xml +++ b/app/api/playedu-course/src/main/resources/mapper/jc/BookDepartmentUserMapper.xml @@ -24,5 +24,22 @@ update_time, tenant_id - + diff --git a/app/api/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/ResourceTranscodeInfoServiceImpl.java b/app/api/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/ResourceTranscodeInfoServiceImpl.java index e1c4889..be7a392 100644 --- a/app/api/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/ResourceTranscodeInfoServiceImpl.java +++ b/app/api/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/ResourceTranscodeInfoServiceImpl.java @@ -155,7 +155,7 @@ public class ResourceTranscodeInfoServiceImpl || timestamp == null || StringUtil.isEmpty(definition) || StringUtil.isEmpty(sign)) { - throw new ServiceException("参数为空"); + throw new ServiceException("参数为空2"); } String str =