Compare commits

...

81 Commits
main ... dev

Author SHA1 Message Date
GoCo
337ba0f42a Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev
merge
2025-08-29 17:21:51 +08:00
GoCo
42eb767979 feat: 🎸 课程列表按最新\最热\推荐排序 2025-08-29 17:21:42 +08:00
Lqc
326e764f29 微调 2025-08-29 16:26:47 +08:00
Lqc
3896f6df85 微调 2025-08-29 16:11:48 +08:00
Lqc
6cf1b91b85 提交考试时计算选择题,多选题,判断题得分 2025-08-29 15:59:54 +08:00
Lqc
61665d749d 获取所有题库 2025-08-29 15:01:33 +08:00
GoCo
bf470b1c79 feat: 🎸 课程总数 2025-08-29 05:12:30 +08:00
Lqc
58ea4b3071 查询考试进度 2025-08-28 14:45:25 +08:00
Lqc
69d2a464cb 随机组卷 2025-08-28 14:35:03 +08:00
Lqc
97419396f6 查询题目详情更改返回结果 2025-08-28 13:49:05 +08:00
GoCo
5861ce2655 Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev
merge
2025-08-28 06:02:07 +08:00
GoCo
a51f6c6e2e feat: 🎸 查询精选活动 2025-08-28 06:01:56 +08:00
GoCo
9d490fbbda feat: 🎸 查询当前教师创建的课程增加关键词和状态参数 2025-08-28 05:37:17 +08:00
Lqc
9dc9b50b1d Merge remote-tracking branch 'origin/dev' into dev 2025-08-27 21:41:17 +08:00
Lqc
e06a4b9f89 提交答案,提交考试,获取试卷初始化 2025-08-27 21:40:42 +08:00
GoCo
5b0e087dcd feat: 🎸 搜索以及获取热搜 2025-08-27 17:17:09 +08:00
Lqc
796f1502b6 考试,获取考试试题 2025-08-26 14:07:34 +08:00
GoCo
a9a2a16618 feat: 🎸 考试 试卷 表生成 2025-08-26 02:25:27 +08:00
GoCo
c48769872d Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev
merge
2025-08-26 02:06:22 +08:00
GoCo
9830e0d3b3 查询高校列表 2025-08-26 02:06:13 +08:00
Lqc
52798ce478 查询题库下题目时,返回复合题下的子题目 2025-08-25 12:46:40 +08:00
Lqc
35ed6f0b1b Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev 2025-08-25 12:45:25 +08:00
GoCo
50e127c505 Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev
merge
2025-08-25 10:55:48 +08:00
GoCo
f2cf55e293 feat: 🎸 首页数据查询接口 2025-08-25 10:55:07 +08:00
小张
520fbcf177 fix:logo标题替换我们云岭智教 2025-08-23 17:44:48 +08:00
Lqc
d9c50d4750 查询题目详情对于复合题返回题目及答案 2025-08-23 14:57:43 +08:00
GoCo
3f2c7877ed feat: 🎸 删除生成文件 2025-08-22 17:00:35 +08:00
GoCo
78de817ca9 Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev
merge
2025-08-22 16:56:26 +08:00
GoCo
6b2ae0f50d feat: 🎸 课程进度查询接口 2025-08-22 16:56:11 +08:00
Lqc
b3fda1650b 冲突 2025-08-22 16:02:46 +08:00
Lqc
d7b8733123 冲突 2025-08-22 16:02:01 +08:00
Lqc
81a6f0ee43 Merge branch 'dev' of http://110.42.96.65:19890/GoCo/OL-LearnPlatform-Backend into dev
# Conflicts:
#	jeecg-boot/jeecg-boot-module/jeecg-module-learn/src/main/java/org/jeecg/modules/biz/controller/RepoBizController.java
2025-08-22 16:01:01 +08:00
Lqc
7f9bd444dd 题目题库 2025-08-22 15:54:27 +08:00
GoCo
049ee30611 feat: 🎸 新建题库 2025-08-22 11:02:57 +08:00
GoCo
0d83336140 feat: 🎸 题库 题目表 2025-08-21 17:56:27 +08:00
Lqc
bf96853b68 作业提交、查询,教师批改 2025-08-21 14:37:41 +08:00
GoCo
4080fa4ce5 feat: 🎸 活动报名表 生成 2025-08-21 12:06:44 +08:00
GoCo
d069086ea4 feat: 🎸 作业提交表gen 2025-08-21 10:26:16 +08:00
GoCo
b4bbcb4d7d fix: 🐛 nginx max body size 2025-08-20 13:05:43 +08:00
GoCo
23ad7f14f9 fix: 🐛 nginx 配置 2025-08-20 13:01:24 +08:00
GoCo
4619edaad8 ci: 🎡 nginx配置 2025-08-20 12:48:48 +08:00
GoCo
593224a478 ci: 🎡 上传文件大小限制 2025-08-20 11:23:47 +08:00
GoCo
8717b32306 feat: 🎸 课程报名、导入学生、上传视频切片接口&dockerfile增加ffmpeg 2025-08-20 05:53:27 +08:00
GoCo
7188b7a500 feat: 🎸 课程报名&查询报名情况接口 2025-08-19 02:49:29 +08:00
GoCo
3d9fda6230 作业+文档章节接口 2025-08-18 17:32:52 +08:00
GoCo
4c160a7bb3 feat: 🎸 课程列表接口,参数查询逻辑补齐 2025-08-18 11:49:27 +08:00
GoCo
d2b61c6d95 feat: 🎸 评论表&课程评论接口 2025-08-16 17:19:41 +08:00
GoCo
de06ae4b92 feat: 🎸 课程章节后台管理页面改弹出框选课 2025-08-16 14:18:07 +08:00
GoCo
595bd526d4 feat: 🎸 用户信息接口,改成dto并配置字段含义 2025-08-15 18:10:01 +08:00
GoCo
960aee1b68 feat: 🎸 用户信息查询接口 2025-08-15 17:53:42 +08:00
GoCo
ec89859f60 feat: 🎸 课程列表携带讲师信息 2025-08-15 17:13:22 +08:00
GoCo
64b7eded58 ci: 🎡 临时解决,上传文件认证失败 2025-08-14 14:09:49 +08:00
GoCo
a4754cb513 ci: 🎡 dockerfile nginx反代请求头 2025-08-14 13:36:37 +08:00
GoCo
00df9d643b ci: 🎡 前端dockerfile nginx反代配置携带x-access-token header 2025-08-14 13:32:04 +08:00
GoCo
d9ef0b8fa6 feat: 🎸 课程、用户信息、活动、师资力量接口 2025-08-14 07:06:05 +08:00
GoCo
02d0d55a9d ci: 🎡 部署脚本调整 2025-08-13 04:57:27 +08:00
GoCo
801e48b660 feat: 🎸 课程接口&用户登录 2025-08-13 04:46:50 +08:00
GoCo
c08fc2bb79 ci: 🎡 minio config 2025-08-12 20:00:14 +08:00
GoCo
2334fae638 ci: 🎡 docker compose 2025-08-12 19:51:39 +08:00
GoCo
880626acfc ci: 🎡 minio 2025-08-12 19:44:45 +08:00
GoCo
8f9e974aad feat: 🎸 课程列表接口-01 2025-08-12 19:17:33 +08:00
962101f37a ci: 🎡 修改部署脚本 2025-08-10 01:45:12 +08:00
lvzhihao
9738eec256 提交资源接口 2025-08-09 15:35:04 +08:00
lvzhihao
7caffa67cc 更改了一下课程状态接口 2025-08-09 15:29:15 +08:00
lvzhihao
5bfea2b020 提交课程章节相关接口 2025-08-09 14:59:43 +08:00
lvzhihao
a496d61524 提交课程分类相关接口 2025-08-09 14:25:23 +08:00
lvzhihao
0427eebee7 提交课程相关接口 2025-08-09 13:31:44 +08:00
lvzhihao
60c7ff577d 删除课程代码 2025-08-09 13:24:01 +08:00
GoCo
025be43257 feat: 🎸 视频上传接口&示例接口 2025-08-09 01:36:44 +08:00
GoCo
e5e0823e7a feat: 🎸 测试表 2025-08-08 20:14:27 +08:00
GoCo
865d3f8f22 tmp 2025-08-08 20:12:01 +08:00
lvzhihao
b992471374 删除课程代码 2025-08-08 18:30:54 +08:00
lvzhihao
bc369ad2dc 课程相关接口 2025-08-08 18:22:40 +08:00
Lzh
a6f8b2cd25 更新 jeecgboot-vue3/Dockerfile 2025-08-08 18:11:01 +08:00
Lzh
97e23b2ad1 更新 docker-compose.yml 2025-08-08 17:52:00 +08:00
Lzh
83b06b7648 更新 jeecgboot-vue3/Dockerfile 2025-08-08 17:45:20 +08:00
lvzhihao
64262ad748 课程相关接口 2025-08-07 21:34:11 +08:00
lvzhihao
6b2ab8eed7 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	jeecg-boot/jeecg-boot-module/jeecg-module-learn/src/main/java/org/jeecg/modules/learn/gen/entity/Course.java
#	jeecg-boot/jeecg-boot-module/jeecg-module-learn/src/main/java/org/jeecg/modules/learn/gen/vue3/Course.data.ts
#	jeecg-boot/jeecg-boot-module/jeecg-module-learn/src/main/java/org/jeecg/modules/learn/gen/vue3/V20250807_1__menu_insert_Course.sql
#	jeecgboot-vue3/src/views/gen/CourseList.vue
#	jeecgboot-vue3/src/views/learn/Course.data.ts
#	jeecgboot-vue3/src/views/learn/CourseList.vue
2025-08-07 21:33:42 +08:00
lvzhihao
4ddb774b32 课程相关接口 2025-08-07 21:29:49 +08:00
GoCo
09a8f99ab8 feat: 🎸 init 2025-08-07 20:23:55 +08:00
GoCo
0922190012 feat: 🎸 init 2025-08-07 19:31:36 +08:00
308 changed files with 23305 additions and 1553 deletions

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "automatic"
}

View File

@ -18,7 +18,10 @@ services:
--max_allowed_packet=128M
--default-authentication-plugin=caching_sha2_password
ports:
- 13306:3306
- 25523:3306
# 添加数据卷挂载将MySQL数据持久化到宿主机目录
volumes:
- /home/visionx/AIOL/mysql-jeecg:/var/lib/mysql
networks:
- jeecg-boot
@ -40,7 +43,7 @@ services:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: vector_db
ports:
- 5432:5432
- 25524:5432
restart: always
networks:
- jeecg-boot
@ -56,7 +59,7 @@ services:
image: jeecg-boot-system
hostname: jeecg-boot-system
ports:
- 8080:8080
- 25525:8080
networks:
- jeecg-boot
jeecg-vue:
@ -69,8 +72,9 @@ services:
networks:
- jeecg-boot
ports:
- 80:80
- 25526:80
networks:
jeecg-boot:
name: jeecg_boot

View File

@ -165,7 +165,7 @@ public class JeecgBootExceptionHandler {
public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
log.error(e.getMessage(), e);
addSysLog(e);
return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");
return Result.error("文件大小超出限制, 请压缩或降低文件质量! ");
}
/**

View File

@ -16,6 +16,16 @@
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-core</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-biz</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,51 @@
package org.jeecg.modules.biz.constant;
/**
* entity_link 表类型常量定义
* source_type主体类型
* target_type内容类型
*/
public final class EntityLinkConst {
private EntityLinkConst() {}
/** 主体类型 */
public static final class SourceType {
private SourceType() {}
// 课程
public static final String COURSE = "course";
// 课程分类
public static final String COURSE_CATEGORY = "course_category";
// 课程章节
public static final String COURSE_SECTION = "course_section";
// 专题字典/专题
public static final String SUBJECT = "subject";
// 活动
public static final String ACTIVITY = "activity";
}
/** 内容类型 */
public static final class TargetType {
private TargetType() {}
// 资源对应资源表
public static final String RESOURCE = "resource";
// 作业对应作业表
public static final String HOMEWORK = "homework";
// 考试对应考试表
public static final String EXAM = "exam";
// 课程
public static final String COURSE = "course";
// 题库
public static final String REPO = "repo";
}
/** 资源类型 0:视频,1:图片,2:文档 */
public static final class ResourceType {
private ResourceType() {}
public static final int VIDEO = 0;
public static final int IMAGE = 1;
public static final int DOCUMENT = 2;
}
}

View File

@ -0,0 +1,71 @@
package org.jeecg.modules.biz.controller;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.biz.service.ActivityBizService;
import org.jeecg.modules.gen.activity.entity.Activity;
import org.jeecg.modules.gen.aioltag.entity.AiolTag;
import org.jeecg.modules.gen.aioltag.mapper.AiolTagMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@RestController
@RequestMapping("/biz/activity")
@Tag(name = "活动")
@Slf4j
public class ActivityBizController {
@Autowired
private ActivityBizService activityBizService;
@Autowired
private AiolTagMapper aiolTagMapper;
@GetMapping("/list")
@Operation(summary = "查询活动列表")
@IgnoreAuth
public Result<List<Activity>> list() {
return Result.OK(activityBizService.getActivityList());
}
@GetMapping("/selected")
@Operation(summary = "查询精选活动")
@IgnoreAuth
public Result<List<Activity>> getSelectedActivities() {
// 1. aiol_tag 表查询 target_type='activity' target_id 列表
QueryWrapper<AiolTag> tagWrapper = new QueryWrapper<>();
tagWrapper.eq("target_type", "activity");
List<AiolTag> tags = aiolTagMapper.selectList(tagWrapper);
if (tags == null || tags.isEmpty()) {
return Result.OK(List.of());
}
// 2. 提取 target_id 列表
List<String> activityIds = tags.stream()
.map(AiolTag::getTargetId)
.filter(id -> id != null && !id.trim().isEmpty())
.collect(Collectors.toList());
if (activityIds.isEmpty()) {
return Result.OK(List.of());
}
// 3. 根据 target_id 列表查询活动数据
QueryWrapper<Activity> activityWrapper = new QueryWrapper<>();
activityWrapper.in("id", activityIds);
List<Activity> activities = activityBizService.list(activityWrapper);
return Result.OK(activities);
}
}

View File

@ -0,0 +1,52 @@
package org.jeecg.modules.biz.controller;
import java.util.List;
import org.jeecg.common.api.vo.Result;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.biz.dto.CommentWithUserInfo;
import org.jeecg.modules.biz.service.ICommentBizService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
@Tag(name = "评论")
@RestController
@RequestMapping("/biz/comment")
@Slf4j
public class CommentBizController {
@Autowired
private ICommentBizService commentBizService;
@GetMapping("/course/{courseId}/list")
@Operation(summary = "查询课程评论列表", description = "根据课程ID查询课程评论列表包含用户信息")
@IgnoreAuth
public Result<List<CommentWithUserInfo>> queryCourseCommentList(@PathVariable("courseId") String courseId) {
List<CommentWithUserInfo> list = commentBizService.getCommentList("course", courseId);
return Result.OK(list);
}
// @GetMapping("/activity/{activityId}/list")
// @Operation(summary = "查询活动评论列表", description = "根据活动ID查询活动评论列表包含用户信息")
// public Result<List<CommentWithUserInfo>> queryActivityCommentList(@PathVariable("activityId") String activityId) {
// List<CommentWithUserInfo> list = commentBizService.getCommentList("activity", activityId);
// return Result.OK(list);
// }
// @GetMapping("/{targetType}/{targetId}/list")
// @Operation(summary = "查询通用评论列表", description = "根据目标类型和目标ID查询评论列表包含用户信息")
// public Result<List<CommentWithUserInfo>> queryCommentList(
// @PathVariable("targetType") String targetType,
// @PathVariable("targetId") String targetId) {
// List<CommentWithUserInfo> list = commentBizService.getCommentList(targetType, targetId);
// return Result.OK(list);
// }
}

View File

@ -0,0 +1,271 @@
package org.jeecg.modules.biz.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.config.shiro.IgnoreAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.modules.biz.dto.CourseWithTeacherInfo;
import org.jeecg.modules.biz.dto.TeacherInfo;
import org.jeecg.modules.biz.service.CourseBizService;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import org.jeecg.modules.gen.homework.entity.Homework;
import org.jeecg.modules.gen.resource.entity.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.Comparator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Tag(name = "课程")
@RestController
@RequestMapping("/biz/course")
@Slf4j
public class CourseBizController {
@Autowired
private CourseBizService courseBizService;
@Autowired
private ISysBaseAPI sysBaseApi;
@GetMapping("/list")
@Operation(summary = "查询课程列表", description = "可根据分类、难度、专题进行检索三个参数可任意传递其中之一、之二或全部每个参数可传递多个值用英文逗号分割不传参或传递all则查询所有课程携带讲师信息")
@IgnoreAuth
public Result<List<CourseWithTeacherInfo>> queryCourseList(
@RequestParam(value = "categoryId", required = false) String categoryId,
@RequestParam(value = "difficulty", required = false) String difficulty,
@RequestParam(value = "subject", required = false) String topic,
@RequestParam(value = "sort", required = false) String sort) {
List<CourseWithTeacherInfo> list = courseBizService.getCourseList(categoryId, difficulty, topic);
if (sort != null) {
switch (sort) {
case "hottest":
list = list.stream()
.sorted(Comparator.comparing(Course::getEnrollCount, Comparator.nullsLast(Integer::compareTo)).reversed())
.collect(Collectors.toList());
break;
case "latest":
list = list.stream()
.sorted(Comparator.comparing(Course::getCreateTime, Comparator.nullsLast(java.util.Date::compareTo)).reversed())
.collect(Collectors.toList());
break;
case "recommend":
default:
// 不处理直接返回
break;
}
}
return Result.OK(list);
}
@GetMapping("/detail")
@Operation(summary = "查询课程详情", description = "根据课程ID查询课程详情")
@IgnoreAuth
public Result<Course> queryCourseDetail(@RequestParam(value = "id") String id) {
Course course = courseBizService.getById(id);
return Result.OK(course);
}
@GetMapping("/subject/list")
@Operation(summary = "查询课程专题列表", description = "返回字典值")
@IgnoreAuth
public Result<List<LabelValue>> querySubjectList() {
List<DictModel> list = sysBaseApi.getDictItems("course_subject");
List<LabelValue> simple = list.stream()
.map(d -> new LabelValue(d.getValue(), d.getLabel() != null ? d.getLabel() : d.getText()))
.collect(Collectors.toList());
return Result.OK(simple);
}
/** 仅返回 value、label 的简单对象 */
private static record LabelValue(String value, String label) {
}
@GetMapping("/difficulty/list")
@Operation(summary = "查询课程难度列表", description = "返回字典值")
@IgnoreAuth
public Result<List<LabelValue>> queryDifficultyList() {
List<DictModel> list = sysBaseApi.getDictItems("course_difficulty");
List<LabelValue> simple = list.stream()
.map(d -> new LabelValue(d.getValue(), d.getLabel() != null ? d.getLabel() : d.getText()))
.collect(Collectors.toList());
return Result.OK(simple);
}
@GetMapping("/category/list")
@Operation(summary = "查询课程分类列表", description = "根据sortOrder降序排序")
@IgnoreAuth
public Result<List<CourseCategory>> queryCategoryList() {
List<CourseCategory> list = courseBizService.getCourseCategoryList();
return Result.OK(list);
}
@GetMapping("/{courseId}/section")
@Operation(summary = "查询课程章节列表", description = "根据课程id查询章节列表type表示章节类型0=视频、1=资料、2=考试、3=作业level表示章节层级0=一级章节、1=二级章节通过parentId记录父子关系前端需自行组织树形结构当前层级的顺序通过sortOrder排序")
@IgnoreAuth
public Result<List<CourseSection>> querySectionList(@PathVariable(value = "courseId") String courseId) {
List<CourseSection> list = courseBizService.getCourseSectionList(courseId);
return Result.OK(list);
}
@GetMapping("/{courseId}/section_video/{sectionId}")
@Operation(summary = "查询视频章节详情", description = "该接口需要携带用户登录token。根据章节id查询章节详情不同类型的章节返回的内容不同")
public Result<List<Resource>> querySectionDetail(@PathVariable(value = "courseId") String courseId, @PathVariable(value = "sectionId") String sectionId) {
// TODO GC 获取用户id根据courseId判断当前用户是否报名课程只有已报名的课程才能查看章节详情
List<Resource> list = courseBizService.getCourseSectionDetail(0, sectionId, Resource.class);
return Result.OK(list);
}
@GetMapping("/{courseId}/section_document/{sectionId}")
@Operation(summary = "查询文档章节详情", description = "该接口需要携带用户登录token。根据章节id查询章节详情不同类型的章节返回的内容不同")
public Result<List<Resource>> querySectionDocumentDetail(@PathVariable(value = "courseId") String courseId, @PathVariable(value = "sectionId") String sectionId) {
// TODO GC 获取用户id根据courseId判断当前用户是否报名课程只有已报名的课程才能查看章节详情
List<Resource> list = courseBizService.getCourseSectionDetail(1, sectionId, Resource.class);
return Result.OK(list);
}
@GetMapping("/{courseId}/section_homework/{sectionId}")
@Operation(summary = "查询作业章节详情", description = "该接口需要携带用户登录token。根据章节id查询章节详情不同类型的章节返回的内容不同")
public Result<List<Homework>> querySectionHomeworkDetail(@PathVariable(value = "courseId") String courseId, @PathVariable(value = "sectionId") String sectionId) {
// TODO GC 获取用户id根据courseId判断当前用户是否报名课程只有已报名的课程才能查看章节详情
List<Homework> list = courseBizService.getCourseSectionDetail(3, sectionId, Homework.class);
return Result.OK(list);
}
@GetMapping("/{courseId}/teachers")
@Operation(summary = "查询课程的授课教师")
@IgnoreAuth
public Result<List<TeacherInfo>> queryTeacherList(@PathVariable(value = "courseId") String courseId) {
List<TeacherInfo> list = courseBizService.getCourseTeacherList(courseId);
return Result.OK(list);
}
@PostMapping("/{courseId}/enroll")
@Operation(summary = "报名课程", description = "该接口需要携带用户登录token。根据课程id报名课程。返回值为报名结果报名成功返回success")
public Result<String> enrollCourse(@PathVariable(value = "courseId") String courseId, HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String username = JwtUtil.getUsername(token);
LoginUser sysUser = sysBaseApi.getUserByName(username);
String result = courseBizService.enrollCourse(courseId, sysUser.getId());
return Result.OK(result);
}
@GetMapping("/{courseId}/is_enrolled")
@Operation(summary = "查询课程是否已报名", description = "该接口需要携带用户登录token。根据课程id查询课程是否已报名。判断返回值的result是否为true")
public Result<Boolean> isEnrolled(@PathVariable(value = "courseId") String courseId, HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String username = JwtUtil.getUsername(token);
LoginUser sysUser = sysBaseApi.getUserByName(username);
boolean isEnrolled = courseBizService.isEnrolled(courseId, sysUser.getId());
return Result.OK(isEnrolled);
}
@GetMapping("/teacher_list")
@Operation(summary = "查询当前教师创建的课程")
public Result<List<Course>> queryTeacherCourseList(
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "status", required = false) Integer status,
HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String username = JwtUtil.getUsername(token);
LoginUser sysUser = sysBaseApi.getUserByName(username);
QueryWrapper<Course> wrapper = new QueryWrapper<Course>().eq("create_by", sysUser.getUsername());
// 课程名关键词检索
if (keyword != null && !keyword.trim().isEmpty()) {
wrapper.like("name", keyword.trim());
}
// 状态检索0 未开始1进行中2已结束
if (status != null) {
wrapper.eq("status", status);
}
List<Course> list = courseBizService.list(wrapper);
return Result.OK(list);
}
@PostMapping("/{courseId}/add_students")
@Operation(summary = "批量导入学生", description = "请求体为JSON格式包含ids字段ids为逗号分隔的学生ID字符串")
public Result<Map<String, Object>> addStudents(@PathVariable(value = "courseId") String courseId, @RequestBody Map<String, Object> requestBody, HttpServletRequest request) {
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String username = JwtUtil.getUsername(token);
LoginUser sysUser = sysBaseApi.getUserByName(username);
// 从Map中获取ids字段
String ids = (String) requestBody.get("ids");
if (ids == null || ids.trim().isEmpty()) {
return Result.error("ids字段不能为空");
}
return Result.OK(courseBizService.addStudents(courseId, ids, sysUser));
}
@GetMapping("/{courseId}/progress")
@Operation(summary = "查询课程学习进度")
public Result<Map<String, Object>> queryCourseProgress(@PathVariable(value = "courseId") String courseId, HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String username = JwtUtil.getUsername(token);
LoginUser sysUser = sysBaseApi.getUserByName(username);
Map<String, Object> progress = courseBizService.getCourseProgress(courseId, sysUser.getId());
return Result.OK(progress);
}
@GetMapping("/count")
@Operation(summary = "查询课程总数", description = "返回系统中所有课程的总数量")
@IgnoreAuth
public Result<Long> queryCourseCount() {
long count = courseBizService.count();
return Result.OK(count);
}
@GetMapping("/test")
@IgnoreAuth
public Result<String> test() {
return Result.OK("test");
}
@GetMapping("/test2")
public Result<String> test2(HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
String username = JwtUtil.getUsername(token);
LoginUser sysUser = sysBaseApi.getUserByName(username);
return Result.OK(sysUser.toString());
}
@GetMapping("/test3")
@IgnoreAuth
public Result<Long> test3() {
long count = courseBizService.count();
return Result.OK(count);
}
}

View File

@ -0,0 +1,436 @@
package org.jeecg.modules.biz.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.gen.exam.entity.Exam;
import org.jeecg.modules.gen.exam.service.IExamService;
import org.jeecg.modules.gen.examanswer.entity.ExamAnswer;
import org.jeecg.modules.gen.examanswer.service.IExamAnswerService;
import org.jeecg.modules.gen.examrecord.entity.ExamRecord;
import org.jeecg.modules.gen.examrecord.service.IExamRecordService;
import org.jeecg.modules.gen.paper.entity.Paper;
import org.jeecg.modules.gen.paper.service.IPaperService;
import org.jeecg.modules.gen.paperquestion.entity.PaperQuestion;
import org.jeecg.modules.gen.paperquestion.service.IPaperQuestionService;
import org.jeecg.modules.gen.question.controller.QuestionController;
import org.jeecg.modules.gen.question.entity.Question;
import org.jeecg.modules.gen.question.entity.QuestionRequest;
import org.jeecg.modules.gen.question.service.IQuestionService;
import org.jeecg.modules.gen.questionoption.entity.QuestionOption;
import org.jeecg.modules.gen.questionoption.service.IQuestionOptionService;
import org.jeecg.modules.gen.questionrepo.entity.QuestionRepo;
import org.jeecg.modules.gen.questionrepo.service.IQuestionRepoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/biz/exam")
@Tag(name = "考试")
@Slf4j
public class ExamBizController {
@Autowired
private IPaperService paperService;
@Autowired
private IExamService examService;
@Autowired
private IPaperQuestionService paperQuestionService;
@Autowired
private IExamAnswerService examAnswerService;
@Autowired
private IExamRecordService examRecordService;
@Autowired
private IQuestionService questionService;
@Autowired
private IQuestionRepoService questionRepoService;
@Autowired
private IQuestionOptionService questionOptionService;
//获取考试试题
@RequestMapping("/getExamQuestions/{examId}")
@Operation(summary = "获取考试试题")
@Transactional
public Result<?> getExamQuestions(@PathVariable String examId, @RequestParam String studentId) {
Exam exam = examService.getById(examId);
if(exam.getPaperId().isEmpty()){
return Result.error("考试未关联试卷");
}
Paper paper = paperService.getById(exam.getPaperId());
//题目id集合
List<String> questionIds;
List<PaperQuestion> paperQuestions = new ArrayList<>();
//随机组卷
if(paper.getGenerateMode()==1){
List<QuestionRepo> list = questionRepoService.list(
new LambdaQueryWrapper<QuestionRepo>().
eq(QuestionRepo::getRepoId, paper.getRepoId())
);
//筛选试卷
questionIds = random(list, paper.getRules());
}else {
//固定组卷
// 获取试卷中的试题关联信息
paperQuestions = paperQuestionService.getQuestions(paper.getId());
// 如果没有试题关联信息直接返回空列表
if (CollectionUtils.isEmpty(paperQuestions)) {
return Result.OK("试卷中没有试题");
}
// 提取所有试题ID
questionIds = paperQuestions.stream()
.map(PaperQuestion::getQuestionId)
.collect(Collectors.toList());
}
if (CollectionUtils.isEmpty(questionIds)) {
return Result.OK("试卷中没有试题");
}
// 从题目表查询试题内容
List<Question> questions = questionService.listByIds(questionIds);
List<Question> sortedQuestions = questions;
// 将试题内容按试卷中的顺序排序
if(paper.getGenerateMode()==0){
Map<String, Question> questionMap = questions.stream()
.collect(Collectors.toMap(Question::getId, question -> question));
sortedQuestions = paperQuestions.stream()
.sorted(Comparator.comparing(PaperQuestion::getOrderNo))
.map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId()))
.collect(Collectors.toList());
}
//获取复选题id
List<String> type5Ids = sortedQuestions.stream()
.filter(question -> question.getType() == 5)
.map(Question::getId)
.collect(Collectors.toList());
//获取复选题所包含的题目
List<Question> type5Questions = new ArrayList<>();
if (!type5Ids.isEmpty()) {
type5Questions = questionService.list(
new LambdaQueryWrapper<Question>()
.in(Question::getParentId, type5Ids)
);
}
// 创建一个映射用于快速查找父ID对应的子题目
Map<String, List<Question>> parentToChildrenMap = type5Questions.stream()
.collect(Collectors.groupingBy(Question::getParentId));
// 将子题目添加到原始列表中保持原有顺序
List<Question> resultQuestions = new ArrayList<>();
for (Question question : questions) {
resultQuestions.add(question);
if (question.getType() == 5) {
List<Question> children = parentToChildrenMap.getOrDefault(question.getId(), Collections.emptyList());
resultQuestions.addAll(children);
}
}
//创建考试答题初始化记录
List<ExamAnswer> examAnswerList = new ArrayList<>();
for (Question resultQuestion : resultQuestions) {
ExamAnswer examAnswer = new ExamAnswer();
examAnswer.setExamId(examId);
examAnswer.setUserId(studentId);
if (resultQuestion != null && StringUtils.isNotEmpty(resultQuestion.getParentId())) {
examAnswer.setParentQuestionId(resultQuestion.getParentId());
}
examAnswer.setQuestionId(resultQuestion.getId());
examAnswerList.add(examAnswer);
}
examAnswerService.saveBatch(examAnswerList);
//创建考试记录
ExamRecord examRecord = new ExamRecord();
examRecord.setExamId(examId);
examRecord.setUserId(studentId);
examRecord.setStatus(0);
examRecordService.save(examRecord);
// 返回排序后的试题总列表
return Result.OK(resultQuestions);
}
@PostMapping("/submitAnswer")
@Operation(summary = "提交答案")
public Result<?> submitAnswer(@RequestBody ExamAnswer examAnswer) {
// 创建查询条件
LambdaUpdateWrapper<ExamAnswer> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(ExamAnswer::getExamId, examAnswer.getExamId())
.eq(ExamAnswer::getUserId, examAnswer.getUserId())
.eq(ExamAnswer::getQuestionId, examAnswer.getQuestionId());
// 更新答案
if (examAnswer.getAnswer() != null) {
updateWrapper.set(ExamAnswer::getAnswer, examAnswer.getAnswer());
}
// 执行更新
return examAnswerService.update(updateWrapper) ? Result.OK() : Result.error("提交答案失败");
}
@PostMapping("/submitExam")
@Operation(summary = "提交考试")
@Transactional
public Result<?> submitExam(@RequestBody ExamRecord examRecord,
HttpServletRequest req) {
examRecord.setIpAddress(getClientIp(req));
examRecord.setDeviceInfo(getDeviceInfo(req));
//修改状态
examRecord.setStatus(1);
// 创建更新条件
LambdaUpdateWrapper<ExamRecord> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(ExamRecord::getExamId, examRecord.getExamId())
.eq(ExamRecord::getUserId, examRecord.getUserId());
// 更新ip
if (examRecord.getIpAddress() != null) {
updateWrapper.set(ExamRecord::getIpAddress, examRecord.getIpAddress());
}
// 更新设备信息
if (examRecord.getDeviceInfo() != null) {
updateWrapper.set(ExamRecord::getDeviceInfo, examRecord.getDeviceInfo());
}
// 阅卷
List<ExamAnswer> gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId());
examAnswerService.updateBatchById(gradedAnswers);
// 更新考试状态提交时间
updateWrapper.
set(ExamRecord::getStatus,1).
set(ExamRecord::getSubmittedAt, new Date());
// 更新
return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败");
}
@GetMapping("/queryExamProgress")
@Operation(summary = "查询考试进度")
public Result<?> queryExamProgress(@RequestParam String examId, @RequestParam String userId) {
Exam byId = examService.getById(examId);
if(byId == null){
return Result.error("考试不存在");
}
//判断考试结束时间
if(byId.getEndTime().before(new Date())){
return Result.error("考试已结束");
}
ExamRecord one = examRecordService.getOne(
new LambdaQueryWrapper<ExamRecord>()
.eq(ExamRecord::getExamId, examId)
.eq(ExamRecord::getUserId, userId)
);
if(one == null){
return Result.error("用户暂未考试,可获取考试题目");
}
return Result.OK(examAnswerService.
list(new LambdaQueryWrapper<ExamAnswer>().
eq(ExamAnswer::getExamId, examId).
eq(ExamAnswer::getUserId, userId))
);
}
//根据考试规则随机组卷
public List<String> random(List<QuestionRepo> list, String rules) {
JSONObject ruleJson = JSON.parseObject(rules);
// 根据规则筛选和随机抽取题目
Map<Integer, List<String>> typeQuestions = new HashMap<>();
// 先按题目类型分组
list.forEach(qr -> {
Question question = questionService.getById(qr.getQuestionId());
if (!typeQuestions.containsKey(question.getType())) {
typeQuestions.put(question.getType(), new ArrayList<>());
}
typeQuestions.get(question.getType()).add(question.getId());
});
// 根据规则随机抽取题目
List<String> questionIds = new ArrayList<>();
for (Integer type : typeQuestions.keySet()) {
int count = ruleJson.getInteger("type"+type + "_count"); // 例如single_choice_count
List<String> typeQuestionIds = typeQuestions.get(type);
// 随机抽取指定数量的题目
if (typeQuestionIds.size() <= count) {
questionIds.addAll(typeQuestionIds);
} else {
// 打乱顺序后取前count个
Collections.shuffle(typeQuestionIds);
questionIds.addAll(typeQuestionIds.subList(0, count));
}
}
return questionIds;
}
//获取ip信息
public String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 对于通过多个代理的情况第一个IP为客户端真实IP,多个IP按照','分割
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
/**
* 批量阅卷
* @param examId 考试ID
* @param userId 用户ID
* @return 阅卷后的答题列表
*/
private List<ExamAnswer> gradeExam(String examId, String userId) {
// 获取学生的答题列表
List<ExamAnswer> examAnswerList = examAnswerService.list(new LambdaQueryWrapper<ExamAnswer>()
.eq(ExamAnswer::getExamId, examId)
.eq(ExamAnswer::getUserId, userId)
);
// 提取所有题目ID
List<String> questionIds = examAnswerList.stream()
.map(ExamAnswer::getQuestionId)
.collect(Collectors.toList());
// 查询题目
List<Question> questions = questionService.list(new LambdaQueryWrapper<Question>()
.in(Question::getId, questionIds)
.lt(Question::getType, 3)
);
// 创建题目ID到题目的映射
Map<String, Question> questionMap = questions.stream()
.collect(Collectors.toMap(Question::getId, question -> question));
// 获取 选择多选判断 题目ID列表
List<String> questionIdsFromQuestions = questions.stream()
.map(Question::getId)
.collect(Collectors.toList());
// 查询这些题目的正确选项
List<QuestionOption> questionOptions = questionOptionService.list(new LambdaQueryWrapper<QuestionOption>()
.in(QuestionOption::getQuestionId, questionIdsFromQuestions)
.eq(QuestionOption::getIzCorrent, 1)
);
// 将选项转换为Map结构为题目ID -> 正确答案选项ID列表
Map<String, List<String>> correctAnswerMap = questionOptions.stream()
.collect(Collectors.groupingBy(
QuestionOption::getQuestionId,
Collectors.mapping(QuestionOption::getId, Collectors.toList())
));
// 遍历学生的答案进行评分
for (ExamAnswer examAnswer : examAnswerList) {
String studentAnswer = examAnswer.getAnswer();
Question question = questionMap.get(examAnswer.getQuestionId());
List<String> correctAnswers = correctAnswerMap.get(examAnswer.getQuestionId());
// 比较答案并设置分数
if (studentAnswer != null && question != null && correctAnswers != null) {
// 将学生答案按逗号分割成列表
List<String> studentAnswers = Arrays.asList(studentAnswer.split(","));
double score = 0.0;
// 根据题目类型进行评分
if (question.getType() == 1 || question.getType() == 2) { // 单选题或判断题
if (studentAnswers.get(0).equals(correctAnswers.get(0))) {
score = question.getScore(); // 使用题目设定的分值
}
} else if (question.getType() == 3) { // 多选题
// 检查学生答案数量是否正确
if (studentAnswers.size() == correctAnswers.size()) {
// 检查每个答案是否都正确
boolean allCorrect = studentAnswers.stream()
.allMatch(correctAnswers::contains);
if (allCorrect) {
score = question.getScore(); // 使用题目设定的分值
}
}
}
examAnswer.setIzCorrect(score> 0.0 ? 1 : 0);
examAnswer.setScore(score);
} else {
examAnswer.setScore(0.0); // 答案为空或题目不存在
}
}
return examAnswerList;
}
//获取设备信息
public String getDeviceInfo(HttpServletRequest request) {
// 获取User-Agent
String userAgent = request.getHeader("User-Agent");
// 解析设备信息
String deviceInfo = parseDeviceInfo(userAgent);
return deviceInfo;
}
private String parseDeviceInfo(String userAgent) {
if (userAgent == null) {
return "Unknown";
}
StringBuilder deviceInfo = new StringBuilder();
// 判断操作系统
if (userAgent.indexOf("Windows") > -1) {
deviceInfo.append("Windows");
} else if (userAgent.indexOf("Mac") > -1) {
deviceInfo.append("Mac");
} else if (userAgent.indexOf("X11") > -1) {
deviceInfo.append("Unix");
} else if (userAgent.indexOf("Android") > -1) {
deviceInfo.append("Android");
} else if (userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) {
deviceInfo.append("iOS");
} else {
deviceInfo.append("Unknown OS");
}
deviceInfo.append(" | ");
// 判断浏览器
if (userAgent.indexOf("MSIE") > -1) {
deviceInfo.append("MSIE");
} else if (userAgent.indexOf("Firefox") > -1) {
deviceInfo.append("Firefox");
} else if (userAgent.indexOf("Chrome") > -1) {
deviceInfo.append("Chrome");
} else if (userAgent.indexOf("Safari") > -1) {
deviceInfo.append("Safari");
} else if (userAgent.indexOf("Opera") > -1) {
deviceInfo.append("Opera");
} else {
deviceInfo.append("Unknown Browser");
}
// 可以添加更多设备信息的判断
// 判断是否是移动设备
boolean isMobile = userAgent.indexOf("Mobile") > -1 ||
userAgent.indexOf("Android") > -1 ||
userAgent.indexOf("iPhone") > -1;
deviceInfo.append(" | ").append(isMobile ? "Mobile" : "PC");
return deviceInfo.toString();
}
}

View File

@ -0,0 +1,53 @@
package org.jeecg.modules.biz.controller;
import org.jeecg.modules.biz.dto.StudentSubmitHomework;
import org.jeecg.modules.gen.homeworksubmit.entity.HomeworkSubmit;
import org.jeecg.modules.gen.homeworksubmit.service.IHomeworkSubmitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import java.util.List;
import org.jeecg.modules.biz.service.IHomeworkBizService;
import org.jeecg.modules.gen.homework.entity.Homework;
@RestController
@RequestMapping("/biz/homework")
@Tag(name = "作业")
@Slf4j
public class HomeworkBizController {
@Autowired
private IHomeworkBizService homeworkBizService;
@Autowired
private IHomeworkSubmitService homeworkSubmitService;
@GetMapping("/course/{courseId}")
@Operation(summary = "查询课程作业")
public Result<List<Homework>> list(@PathVariable String courseId) {
return Result.OK(homeworkBizService.listByCourseId(courseId));
}
@PostMapping("submit")
@Operation(summary = "提交作业")
public Result<String> submit(@RequestBody StudentSubmitHomework studentSubmitHomework) {
return Result.OK(homeworkSubmitService.submit(studentSubmitHomework)?"提交成功":"提交失败");
}
@GetMapping("submitted/{studentId}")
@Operation(summary = "查询我已提交的作业")
public Result<List<HomeworkSubmit>> submitted(@PathVariable String studentId) {
return Result.OK(homeworkSubmitService.submitted(studentId));
}
@PostMapping("correct/{homeworkSubmitId}")
@Operation(summary = "教师批改作业")
public Result<Integer> correct(@PathVariable String homeworkSubmitId, @RequestParam Integer score,
@RequestParam String comment,@RequestParam String teacherId) {
return Result.OK(homeworkSubmitService.correct(homeworkSubmitId, score,comment, teacherId));
}
}

View File

@ -0,0 +1,173 @@
package org.jeecg.modules.biz.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.biz.dto.CommentWithUserInfo;
import org.jeecg.modules.biz.service.ICommentBizService;
import org.jeecg.modules.gen.contentconfig.entity.ContentConfig;
import org.jeecg.modules.gen.contentconfig.mapper.ContentConfigMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.Map;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.course.mapper.CourseMapper;
@Tag(name = "首页")
@RestController
@RequestMapping("/biz/index")
@Slf4j
public class IndexBizController {
@Autowired
private ContentConfigMapper contentConfigMapper;
@Autowired
private ICommentBizService commentBizService;
@Autowired(required = false)
private StringRedisTemplate stringRedisTemplate;
@Autowired
private CourseMapper courseMapper;
private static final String HOT_SEARCH_ZSET_KEY = "hot:search";
@GetMapping("/content")
@Operation(summary = "查询首页内容")
@IgnoreAuth
public Result<String> queryContent(@RequestParam String contentKey) {
ContentConfig contentConfig = contentConfigMapper.selectOne(new QueryWrapper<ContentConfig>().eq("content_key", contentKey));
if (contentConfig == null) {
return Result.error("内容配置不存在");
}
return Result.OK(contentConfig.getContentValue());
}
@GetMapping("/statistics")
@Operation(summary = "查询首页数据统计")
@IgnoreAuth
public Result<Map<String, Object>> queryStatistics() {
Map<String, Object> map = new HashMap<>();
// 定义统计项的配置键
String[] statisticsKeys = {"xxsp", "mszj", "pxjc", "zysc", "zxsy"};
// 从配置表查询每个统计项的值
for (String key : statisticsKeys) {
ContentConfig contentConfig = contentConfigMapper.selectOne(
new QueryWrapper<ContentConfig>().eq("content_key", key)
);
if (contentConfig != null && contentConfig.getContentValue() != null) {
try {
// 尝试解析为数字如果失败则使用默认值0
Integer value = Integer.parseInt(contentConfig.getContentValue());
map.put(key, value);
} catch (NumberFormatException e) {
log.warn("配置项 {} 的值 {} 不是有效数字使用默认值0", key, contentConfig.getContentValue());
map.put(key, 0);
}
} else {
log.warn("配置项 {} 不存在使用默认值0", key);
map.put(key, 0);
}
}
return Result.OK(map);
}
@GetMapping("/selected_comments")
@Operation(summary = "查询精选评论")
@IgnoreAuth
public Result<List<CommentWithUserInfo>> querySelectedComments() {
// 查询精选评论包含用户信息
List<CommentWithUserInfo> comments = commentBizService.getAllSelectedComments();
return Result.OK(comments);
}
@GetMapping("/hot_search")
@Operation(summary = "查询热门搜索记录(关键词+搜索次数Redis ZSet 排名)")
@IgnoreAuth
public Result<List<Map<String, Object>>> queryHotSearch(@RequestParam(defaultValue = "10") Integer limit) {
if (limit == null || limit <= 0) {
limit = 10;
}
if (stringRedisTemplate == null) {
return Result.error("Redis 未配置,无法查询热门搜索");
}
Set<TypedTuple<String>> tuples = stringRedisTemplate.opsForZSet()
.reverseRangeWithScores(HOT_SEARCH_ZSET_KEY, 0, limit - 1);
List<Map<String, Object>> result = new ArrayList<>();
if (tuples != null) {
for (TypedTuple<String> tuple : tuples) {
if (tuple == null) {
continue;
}
Map<String, Object> item = new HashMap<>();
item.put("keyword", tuple.getValue());
item.put("count", tuple.getScore() == null ? 0 : tuple.getScore().longValue());
result.add(item);
}
}
return Result.OK(result);
}
@GetMapping("/search")
@Operation(summary = "全局搜索课程name/description/school")
@IgnoreAuth
public Result<List<Course>> globalSearch(
@RequestParam String keyword,
@RequestParam(required = false, defaultValue = "20") Integer limit
) {
if (limit == null || limit <= 0) {
limit = 20;
}
if (limit > 100) {
limit = 100;
}
if (keyword == null || keyword.trim().isEmpty()) {
return Result.OK(new ArrayList<>());
}
if (keyword.trim().length() < 2) {
return Result.error("关键词长度至少为2个字符");
}
// 记录关键词到 Redis 热搜
if (stringRedisTemplate != null) {
try {
stringRedisTemplate.opsForZSet().incrementScore(HOT_SEARCH_ZSET_KEY, keyword.trim(), 1D);
} catch (Exception e) {
log.warn("记录热搜关键词到 Redis 失败: {}", keyword, e);
}
}
String kw = keyword.trim();
QueryWrapper<Course> wrapper = new QueryWrapper<>();
wrapper.lambda()
.like(Course::getName, kw)
.or()
.like(Course::getDescription, kw)
.or()
.like(Course::getSchool, kw);
List<Course> list = courseMapper.selectList(wrapper.last("limit " + limit));
return Result.OK(list);
}
}

View File

@ -0,0 +1,207 @@
package org.jeecg.modules.biz.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.biz.constant.EntityLinkConst;
import org.jeecg.modules.biz.dto.QuestionAnswerDTO;
import org.jeecg.modules.biz.service.EntityLinkBizService;
import org.jeecg.modules.gen.question.entity.Question;
import org.jeecg.modules.gen.question.service.IQuestionService;
import org.jeecg.modules.gen.questionanswer.entity.QuestionAnswer;
import org.jeecg.modules.gen.questionanswer.service.IQuestionAnswerService;
import org.jeecg.modules.gen.questionoption.entity.QuestionOption;
import org.jeecg.modules.gen.questionoption.service.IQuestionOptionService;
import org.jeecg.modules.gen.questionrepo.service.IQuestionRepoService;
import org.jeecg.modules.gen.repo.entity.Repo;
import org.jeecg.modules.gen.repo.mapper.RepoMapper;
import org.jeecg.modules.gen.repo.service.IRepoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/biz/repo")
@Tag(name = "题库")
@Tag(name = "题库题目")
@Slf4j
public class RepoBizController {
@Autowired
private RepoMapper repoMapper;
@Autowired
private IRepoService repoService;
@Autowired
private IQuestionRepoService questionRepoService;
@Autowired
private EntityLinkBizService entityLinkBizService;
@Autowired
private IQuestionService questionService;
@Autowired
private IQuestionOptionService questionOptionService;
@Autowired
private IQuestionAnswerService questionAnswerService;
@PostMapping("course_add")
@Operation(summary = "获取课程下的题库")
@Transactional
public Result<Integer> correct(@RequestBody Map<String, Object> data) {
String title = (String) data.get("title");
String remark = (String) data.get("remark");
String courseId = (String) data.get("courseId");
Repo repo = new Repo();
repo.setTitle(title);
repo.setRemark(remark);
repoMapper.insert(repo);
entityLinkBizService.save(EntityLinkConst.SourceType.COURSE, courseId, EntityLinkConst.TargetType.REPO, repo.getId());
return Result.OK(repo.getId());
}
@GetMapping("repoList")
@Operation(summary = "获取所有题库")
public Result<List<Repo>> repoList() {
return Result.ok(repoService.list());
}
@PostMapping(value = "/courseAdd")
@Operation(summary = "课程新建题库")
public Result<String> courseAdd(@RequestBody Repo repo) {
return repoService.save(repo) ? Result.OK("添加成功!") : Result.error("添加失败!");
}
@GetMapping("/questionList/{repoId}")
@Operation(summary = "查询题库下题目")
public Result<List<Question>> questionList(@PathVariable String repoId) {
// 获取题库中的题目ID列表
List<String> repoQuestionIds = questionRepoService.questionList(repoId);
if (repoQuestionIds.isEmpty()) {
return Result.error("该题库下没有题目或该题库不存在");
}
// 根据ID列表查询题目
List<Question> questions = questionService.listByIds(repoQuestionIds);
if(questions.isEmpty()){
return Result.error("题目不存在");
}
//获取复选题id
List<String> type5Ids = questions.stream()
.filter(question -> question.getType() == 5)
.map(Question::getId)
.collect(Collectors.toList());
//获取复选题所包含的题目
List<Question> type5Questions = new ArrayList<>();
if (!type5Ids.isEmpty()) {
type5Questions = questionService.list(
new LambdaQueryWrapper<Question>()
.in(Question::getParentId, type5Ids)
);
}
// 创建一个映射用于快速查找父ID对应的子题目
Map<String, List<Question>> parentToChildrenMap = type5Questions.stream()
.collect(Collectors.groupingBy(Question::getParentId));
// 将子题目添加到原始列表中保持原有顺序
List<Question> resultQuestions = new ArrayList<>();
for (Question question : questions) {
resultQuestions.add(question);
if (question.getType() == 5) {
List<Question> children = parentToChildrenMap.getOrDefault(question.getId(), Collections.emptyList());
resultQuestions.addAll(children);
}
}
return Result.ok(resultQuestions);
}
@GetMapping("course_list")
@Operation(summary = "获取课程下的题库")
public Result<List<Repo>> courseList(@RequestParam String courseId) {
List<String> targetIds = entityLinkBizService.listTargetIds(EntityLinkConst.SourceType.COURSE, courseId, EntityLinkConst.TargetType.REPO);
if (targetIds.size() > 0) {
List<Repo> list = repoMapper.selectByIds(targetIds);
return Result.OK(list);
} else {
return Result.OK(new ArrayList<>());
}
}
@GetMapping("/repoList/{questionId}")
@Operation(summary = "查询题目详情")
public Result<?> questionDetail(@PathVariable String questionId) {
Question rootQuestion = questionService.getById(questionId);
if (rootQuestion == null) {
return Result.error("题目不存在");
}
QuestionAnswerDTO questionAnswerDTO = new QuestionAnswerDTO();
questionAnswerDTO.setQuestion(rootQuestion);
if (rootQuestion.getType() >= 0 && rootQuestion.getType() <= 2) {
questionAnswerDTO.setAnswer(choiceDetail(questionId));
return Result.ok(questionAnswerDTO);
} else if (rootQuestion.getType() == 3 || rootQuestion.getType() == 4) {
questionAnswerDTO.setAnswer(answerDetail(questionId));
return Result.ok(questionAnswerDTO);
} else {
//查询复合题所包含的题目
List<Question> list = questionService.list(
new LambdaQueryWrapper<Question>().
eq(Question::getParentId, questionId)
);
//根据题目类型进行分组false选择多选判断题true填空简答题
Map<Boolean, List<Question>> groupedQuestions = list.stream()
.collect(Collectors.partitioningBy(
q -> q.getType() > 2
));
//获取选择题多选题判断题答案
List<Question> question = groupedQuestions.get(false);
if (!question.isEmpty()) {
question.forEach(q -> {
QuestionAnswerDTO qad = new QuestionAnswerDTO();
qad.setQuestion(q);
qad.setAnswer(choiceDetail(q.getId()));
questionAnswerDTO.getChildren().add(qad);
});
}
//获取填空题简答题答案
List<Question> question1 = groupedQuestions.get(true);
if (!question1.isEmpty()) {
question1.forEach(q -> {
QuestionAnswerDTO qad = new QuestionAnswerDTO();
qad.setQuestion(q);
qad.setAnswer(answerDetail(q.getId()));
questionAnswerDTO.getChildren().add(qad);
});
}
return Result.ok(questionAnswerDTO);
}
}
//查询选择题多选题判断题答案
public List<QuestionOption> choiceDetail(String questionId) {
return questionOptionService.list(
new LambdaQueryWrapper<QuestionOption>().
eq(QuestionOption::getQuestionId, questionId).
orderByAsc(QuestionOption::getOrderNo)
);
}
//查询填空题简答题答案
public List<QuestionAnswer> answerDetail(String questionId) {
return questionAnswerService.list(
new LambdaQueryWrapper<QuestionAnswer>().
eq(QuestionAnswer::getQuestionId, questionId).
orderByAsc(QuestionAnswer::getOrderNo)
);
}
}

View File

@ -0,0 +1,87 @@
package org.jeecg.modules.biz.controller;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.jeecg.common.api.vo.Result;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.biz.constant.EntityLinkConst;
import org.jeecg.modules.biz.service.EntityLinkBizService;
import org.jeecg.modules.biz.service.ResourceBizService;
import org.jeecg.modules.gen.resource.entity.Resource;
import io.swagger.v3.oas.annotations.Operation;
@Tag(name = "资源")
@RestController
@RequestMapping("/biz/resource")
@Slf4j
public class ResourceBizController {
@Autowired
private ResourceBizService resourceBizService;
@Autowired
private EntityLinkBizService entityLinkBizService;
@GetMapping("/feature")
@Operation(summary = "查询精品资源")
@IgnoreAuth
public Result<List<Resource>> queryFeatureResource() {
List<Resource> list = resourceBizService.list(new QueryWrapper<Resource>().eq("iz_featured", 1));
return Result.OK(list);
}
@GetMapping("/video")
@Operation(summary = "按课程分类查询视频资源")
@IgnoreAuth
public Result<List<Resource>> queryVideoResource(@RequestParam("categoryId") String courseCategoryId) {
List<String> targetIds = entityLinkBizService.listTargetIds(EntityLinkConst.SourceType.COURSE_CATEGORY, courseCategoryId, EntityLinkConst.TargetType.RESOURCE);
List<Resource> list = new ArrayList<>();
for (String targetId : targetIds) {
Resource resource = resourceBizService.getById(targetId);
if (resource.getType() == EntityLinkConst.ResourceType.VIDEO) {
list.add(resource);
}
}
return Result.OK(list);
}
@GetMapping("/image")
@Operation(summary = "按课程分类查询图片资源")
@IgnoreAuth
public Result<List<Resource>> queryImageResource(@RequestParam("categoryId") String courseCategoryId) {
List<String> targetIds = entityLinkBizService.listTargetIds(EntityLinkConst.SourceType.COURSE_CATEGORY, courseCategoryId, EntityLinkConst.TargetType.RESOURCE);
List<Resource> list = new ArrayList<>();
for (String targetId : targetIds) {
Resource resource = resourceBizService.getById(targetId);
if (resource.getType() == EntityLinkConst.ResourceType.IMAGE) {
list.add(resource);
}
}
return Result.OK(list);
}
@PostMapping("/upload")
@Operation(summary = "课程视频文件上传", description = "课程视频文件上传返回各清晰度的m3u8文件地址")
public Result<Map<String, String>> upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
if (file == null || file.isEmpty()) return Result.error("没有找到上传的文件");
Map<String, String> qualityUrls = resourceBizService.uploadHls(file, request);
return Result.OK(qualityUrls);
}
}

View File

@ -0,0 +1,204 @@
package org.jeecg.modules.biz.controller;
import org.jeecg.config.shiro.IgnoreAuth;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.jeecg.modules.biz.dto.TeacherInfo;
import org.jeecg.modules.biz.dto.UserInfoResponse;
import org.jeecg.modules.biz.service.UserBizService;
import org.jeecg.modules.gen.userinfo.entity.UserInfo;
import org.jeecg.modules.gen.userinfo.mapper.UserInfoMapper;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.*;
import org.jeecg.common.system.vo.DictModel;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
@Tag(name = "03-用户管理")
@RestController
@RequestMapping("/biz/user")
@Slf4j
public class UserBizController {
@Autowired
private ISysUserService sysUserService;
@Autowired
private RedisUtil redisUtil;
@Autowired
private UserBizService userBizService;
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
private ISysBaseAPI sysBaseApi;
@PostMapping("/login")
@Operation(summary = "用户登录")
@IgnoreAuth
public Result<JSONObject> login(@RequestBody Map<String, String> user, HttpServletRequest request) {
Result<JSONObject> result = new Result<JSONObject>();
String username = user.get("username");
String password = user.get("password");
if (isLoginFailOvertimes(username)) {
return result.error500("该用户登录失败次数过多请于10分钟后再次登录");
}
// step.2 校验用户是否存在且有效
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getUsername, username);
SysUser sysUser = sysUserService.getOne(queryWrapper);
Result<?> checkResult = sysUserService.checkUserIsEffective(sysUser);
if (!checkResult.isSuccess()) {
return result.error500(checkResult.getMessage());
}
// step.3 校验用户名或密码是否正确
String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
String syspassword = sysUser.getPassword();
if (!syspassword.equals(userpassword)) {
addLoginFailOvertimes(username);
result.error500("用户名或密码错误");
return result;
}
// step.4 登录成功获取用户信息
JSONObject obj = new JSONObject(new LinkedHashMap<>());
// 1.生成token
String token = JwtUtil.sign(username, syspassword);
// 设置token缓存有效时间
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
obj.put("token", token);
// TODO 查询用户信息
result.setResult(obj);
result.success("登录成功");
return result;
}
/**
* 登录失败超出次数5 返回true
*
* @param username
* @return
*/
private boolean isLoginFailOvertimes(String username) {
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
if (failTime != null) {
Integer val = Integer.parseInt(failTime.toString());
if (val > 5) {
return true;
}
}
return false;
}
/**
* 记录登录失败次数
*
* @param username
*/
private void addLoginFailOvertimes(String username) {
String key = CommonConstant.LOGIN_FAIL + username;
Object failTime = redisUtil.get(key);
Integer val = 0;
if (failTime != null) {
val = Integer.parseInt(failTime.toString());
}
// 10分钟一分钟为60s
redisUtil.set(key, ++val, 600);
}
@GetMapping("/all_teachers")
@Operation(summary = "查询师资力量", description = "categoryId为all则查询全部")
@IgnoreAuth
public Result<List<TeacherInfo>> queryAllTeachers(@RequestParam("categoryId") String categoryId) {
List<TeacherInfo> list = userBizService.queryAllTeachers(categoryId);
return Result.OK(list);
}
@GetMapping("/info")
@Operation(summary = "查询用户信息", description = "通过JWT token获取当前用户的详细信息包括基本信息、角色和扩展信息")
public Result<UserInfoResponse> queryUserInfo(HttpServletRequest request) {
try {
// 1. 从JWT中获取用户名
String username = JwtUtil.getUserNameByToken(request);
if (username == null || username.trim().isEmpty()) {
return Result.error(401, "用户未登录或token无效");
}
// 2. 根据用户名查询系统用户信息
SysUser sysUser = sysUserService.getUserByName(username);
if (sysUser == null) {
return Result.error(404, "用户不存在");
}
// 3. 查询用户角色
List<String> roles = sysUserService.getUserRolesSet(username).stream()
.collect(Collectors.toList());
// 4. 根据用户ID查询user_info表信息
UserInfo userInfo = userInfoMapper.selectOne(
new QueryWrapper<UserInfo>().eq("user_id", sysUser.getId()));
// 5. 构建返回结果
UserInfoResponse response = new UserInfoResponse();
// 基本用户信息
UserInfoResponse.BaseInfo baseInfo = new UserInfoResponse.BaseInfo();
BeanUtils.copyProperties(sysUser, baseInfo);
response.setBaseInfo(baseInfo);
response.setRoles(roles);
// 扩展用户信息
if (userInfo != null) {
UserInfoResponse.ExtendedInfo extendedInfo = new UserInfoResponse.ExtendedInfo();
BeanUtils.copyProperties(userInfo, extendedInfo);
response.setExtendedInfo(extendedInfo);
}
return Result.OK(response);
} catch (Exception e) {
log.error("查询用户信息失败:" + e.getMessage(), e);
return Result.error(500, "查询用户信息失败:" + e.getMessage());
}
}
@GetMapping("/schools")
@Operation(summary = "查询学校列表")
@IgnoreAuth
public Result<List<String>> querySchools() {
List<DictModel> list = sysBaseApi.getDictItems("school_list");
List<String> schools = list.stream()
.map(d -> d.getLabel())
.collect(Collectors.toList());
return Result.OK(schools);
}
}

View File

@ -0,0 +1,20 @@
package org.jeecg.modules.biz.dto;
import org.jeecg.modules.gen.comment.entity.Comment;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(description = "评论信息(包含用户信息)")
public class CommentWithUserInfo extends Comment {
@Schema(description = "用户姓名")
private String userName;
@Schema(description = "用户头像")
private String userAvatar;
@Schema(description = "用户标签")
private String userTag;
}

View File

@ -0,0 +1,15 @@
package org.jeecg.modules.biz.dto;
import org.jeecg.modules.gen.course.entity.Course;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(description = "课程信息(包含讲师信息)")
public class CourseWithTeacherInfo extends Course {
@Schema(description = "授课讲师列表")
private List<TeacherInfo> teacherList;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.biz.dto;
import lombok.Data;
import org.jeecg.modules.gen.question.entity.Question;
import java.util.ArrayList;
import java.util.List;
@Data
public class QuestionAnswerDTO {
//题目内容
private Question question;
//答案
private List<?> answer;
//子题目列表
private List<QuestionAnswerDTO> children = new ArrayList<>();
}

View File

@ -0,0 +1,25 @@
package org.jeecg.modules.biz.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "学生提交作业")
public class StudentSubmitHomework {
/**作业id*/
@Schema(description = "作业id")
private String homeworkId;
/**学生id*/
@Schema(description = "学生id")
private String studentId;
/**作业内容*/
@Schema(description = "作业内容")
private String content;
/**附件*/
@Schema(description = "附件")
private String attachment;
/**状态*/
@Schema(description = "状态")
private Integer status;
}

View File

@ -0,0 +1,26 @@
package org.jeecg.modules.biz.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "讲师信息")
public class TeacherInfo {
@Schema(description = "讲师ID")
private String id;
@Schema(description = "讲师姓名")
private String name;
@Schema(description = "讲师头像")
private String avatar;
@Schema(description = "职称")
private String title;
@Schema(description = "标签")
private String tag;
@Schema(description = "显示顺序")
private Integer sortOrder;
}

View File

@ -0,0 +1,73 @@
package org.jeecg.modules.biz.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
@Schema(description = "用户信息响应对象")
public class UserInfoResponse {
@Schema(description = "用户基本信息")
private BaseInfo baseInfo;
@Schema(description = "用户角色列表")
private List<String> roles;
@Schema(description = "扩展用户信息")
private ExtendedInfo extendedInfo;
@Data
@Schema(description = "用户基本信息")
public static class BaseInfo {
@Schema(description = "用户ID")
private String id;
@Schema(description = "用户名")
private String username;
@Schema(description = "真实姓名")
private String realname;
@Schema(description = "头像")
private String avatar;
@Schema(description = "手机号")
private String phone;
@Schema(description = "邮箱")
private String email;
@Schema(description = "性别(1-男2-女)")
private Integer sex;
@Schema(description = "生日")
private Date birthday;
@Schema(description = "状态(1-正常2-冻结)")
private Integer status;
}
@Data
@Schema(description = "扩展用户信息")
public static class ExtendedInfo {
@Schema(description = "专业")
private String major;
@Schema(description = "学院")
private String college;
@Schema(description = "学历")
private String education;
@Schema(description = "职称")
private String title;
@Schema(description = "标签")
private String tag;
@Schema(description = "显示顺序")
private Integer sortOrder;
}
}

View File

@ -0,0 +1,13 @@
package org.jeecg.modules.biz.service;
import org.jeecg.modules.gen.activity.entity.Activity;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
public interface ActivityBizService extends IService<Activity> {
/**
* 查询活动列表
* @return
*/
List<Activity> getActivityList();
}

View File

@ -0,0 +1,99 @@
package org.jeecg.modules.biz.service;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.biz.dto.CourseWithTeacherInfo;
import org.jeecg.modules.biz.dto.TeacherInfo;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 课程业务
*/
public interface CourseBizService extends IService<Course> {
/**
* 上传视频并切片为 HLSm3u8+ts按配置(local|minio|alioss)上传返回 m3u8 的路径/URL
* @param file 上传的视频文件
* @param request 用于读取 header 或环境配置
* @return m3u8 路径/URL
* @throws Exception 处理异常
*/
String uploadHls(MultipartFile file, HttpServletRequest request) throws Exception;
/**
* 根据分类难度专题查询课程列表包含讲师信息
* @param categoryId
* @param difficulty
* @param topic
* @return
*/
List<CourseWithTeacherInfo> getCourseList(String categoryId, String difficulty, String topic);
/**
* 查询课程分类列表
* @return
*/
List<CourseCategory> getCourseCategoryList();
/**
* 查询指定课程下的章节列表
* @param courseId
* @return
*/
List<CourseSection> getCourseSectionList(String courseId);
/**
* 查询章节详情泛型
* @param type 章节类型0=视频1=资料2=考试3=作业
* @param sectionId 章节ID
* @param clazz 期望返回的实体类型
* @return 指定类型的列表
*/
<T> List<T> getCourseSectionDetail(Integer type, String sectionId, Class<T> clazz);
/**
* 查询课程的授课教师
* @param courseId
* @return
*/
List<TeacherInfo> getCourseTeacherList(String courseId);
/**
* 报名课程
* @param courseId
* @param id
* @return
*/
String enrollCourse(String courseId, String id);
/**
* 查询课程是否已报名
* @param courseId
* @param id
* @return
*/
boolean isEnrolled(String courseId, String id);
/**
* 批量导入学生
* @param courseId
* @param ids
* @param sysUser
* @return
*/
Map<String, Object> addStudents(String courseId, String ids, LoginUser sysUser);
Map<String, Object> getCourseProgress(String courseId, String id);
}

View File

@ -0,0 +1,26 @@
package org.jeecg.modules.biz.service;
import org.jeecg.modules.gen.entitylink.entity.EntityLink;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface EntityLinkBizService extends IService<EntityLink>{
/**
* 根据主体与内容类型查询绑定的 target_id 列表
* @param sourceType 主体类型
* @param sourceId 主体ID
* @param targetType 内容类型
* @return target_id 列表去重
*/
List<String> listTargetIds(String sourceType, String sourceId, String targetType);
/**
* 保存主体与内容类型的绑定关系
* @param sourceType 主体类型
* @param sourceId 主体ID
* @param targetType 内容类型
* @param targetId 内容ID
*/
void save(String sourceType, String sourceId, String targetType, String targetId);
}

View File

@ -0,0 +1,26 @@
package org.jeecg.modules.biz.service;
import java.util.List;
import org.jeecg.modules.biz.dto.CommentWithUserInfo;
import org.jeecg.modules.gen.comment.entity.*;
import com.baomidou.mybatisplus.extension.service.IService;
public interface ICommentBizService extends IService<Comment> {
/**
* 根据目标类型和目标ID查询评论列表包含用户信息
* @param targetType 目标类型
* @param targetId 目标ID
* @return
*/
List<CommentWithUserInfo> getCommentList(String targetType, String targetId);
/**
* 查询所有精选评论列表包含用户信息
* @return
*/
List<CommentWithUserInfo> getAllSelectedComments();
}

View File

@ -0,0 +1,18 @@
package org.jeecg.modules.biz.service;
import java.util.List;
import org.jeecg.modules.gen.homework.entity.Homework;
import com.baomidou.mybatisplus.extension.service.IService;
public interface IHomeworkBizService extends IService<Homework> {
/**
* 查询某课程章节下的作业
* @param courseId
* @return
*/
List<Homework> listByCourseId(String courseId);
}

View File

@ -0,0 +1,25 @@
package org.jeecg.modules.biz.service;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import org.jeecg.modules.gen.resource.entity.Resource;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 资源业务
*/
public interface ResourceBizService extends IService<Resource> {
/**
* 上传视频并切片为 HLSm3u8+ts按配置(local|minio|alioss)上传返回各清晰度的 m3u8 路径/URL
* @param file 上传的视频文件
* @param request 用于读取 header 或环境配置
* @return 各清晰度的 m3u8 路径/URLMap的key为清晰度名称"480p", "720p", "1080p"value为对应的URL
* @throws Exception 处理异常
*/
Map<String, String> uploadHls(MultipartFile file, HttpServletRequest request) throws Exception;
}

View File

@ -0,0 +1,16 @@
package org.jeecg.modules.biz.service;
import java.util.List;
import org.jeecg.modules.biz.dto.TeacherInfo;
import org.jeecg.modules.gen.userinfo.entity.UserInfo;
import com.baomidou.mybatisplus.extension.service.IService;
public interface UserBizService extends IService<UserInfo> {
/**
* 师资力量
* @return
*/
List<TeacherInfo> queryAllTeachers(String categoryId);
}

View File

@ -0,0 +1,20 @@
package org.jeecg.modules.biz.service.impl;
import java.util.List;
import org.jeecg.modules.biz.service.ActivityBizService;
import org.jeecg.modules.gen.activity.entity.Activity;
import org.jeecg.modules.gen.activity.mapper.ActivityMapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@Service
public class ActivityBizServiceImpl extends ServiceImpl<ActivityMapper, Activity> implements ActivityBizService {
@Override
public List<Activity> getActivityList() {
return baseMapper.selectList(null);
}
}

View File

@ -0,0 +1,107 @@
package org.jeecg.modules.biz.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.jeecg.modules.biz.dto.CommentWithUserInfo;
import org.jeecg.modules.biz.service.ICommentBizService;
import org.jeecg.modules.gen.comment.entity.Comment;
import org.jeecg.modules.gen.comment.mapper.CommentMapper;
import org.jeecg.modules.gen.userinfo.entity.UserInfo;
import org.jeecg.modules.gen.userinfo.mapper.UserInfoMapper;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@Service
public class CommentBizServiceImpl extends ServiceImpl<CommentMapper, Comment> implements ICommentBizService {
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
private SysUserMapper sysUserMapper;
@Override
public List<CommentWithUserInfo> getCommentList(String targetType, String targetId) {
// 1. 根据目标类型和目标ID查询评论列表
QueryWrapper<Comment> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("target_type", targetType)
.eq("target_id", targetId)
.orderByDesc("iz_top") // 置顶评论在前
.orderByDesc("create_time"); // 按时间倒序
List<Comment> comments = this.list(queryWrapper);
// 2. 根据userid关联查询用户信息构建包含用户信息的评论列表
List<CommentWithUserInfo> result = new ArrayList<>();
for (Comment comment : comments) {
CommentWithUserInfo commentWithUser = new CommentWithUserInfo();
// 复制评论基本信息
BeanUtils.copyProperties(comment, commentWithUser);
// 查询用户基本信息
SysUser sysUser = sysUserMapper.selectById(comment.getUserId());
if (sysUser != null) {
commentWithUser.setUserName(sysUser.getRealname());
commentWithUser.setUserAvatar(sysUser.getAvatar());
// 查询用户扩展信息
UserInfo userInfo = userInfoMapper.selectOne(
new QueryWrapper<UserInfo>().eq("user_id", comment.getUserId())
);
if (userInfo != null) {
commentWithUser.setUserTag(userInfo.getTag());
}
}
result.add(commentWithUser);
}
// 3. 返回评论列表
return result;
}
@Override
public List<CommentWithUserInfo> getAllSelectedComments() {
// 1. 查询所有评论按置顶和时间排序
QueryWrapper<Comment> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("iz_top") // 置顶评论在前
.orderByDesc("create_time"); // 按时间倒序
List<Comment> comments = this.list(queryWrapper);
// 2. 根据userid关联查询用户信息构建包含用户信息的评论列表
List<CommentWithUserInfo> result = new ArrayList<>();
for (Comment comment : comments) {
CommentWithUserInfo commentWithUser = new CommentWithUserInfo();
// 复制评论基本信息
BeanUtils.copyProperties(comment, commentWithUser);
// 查询用户基本信息
SysUser sysUser = sysUserMapper.selectById(comment.getUserId());
if (sysUser != null) {
commentWithUser.setUserName(sysUser.getRealname());
commentWithUser.setUserAvatar(sysUser.getAvatar());
// 查询用户扩展信息
UserInfo userInfo = userInfoMapper.selectOne(
new QueryWrapper<UserInfo>().eq("user_id", comment.getUserId())
);
if (userInfo != null) {
commentWithUser.setUserTag(userInfo.getTag());
}
}
result.add(commentWithUser);
}
// 3. 返回评论列表
return result;
}
}

View File

@ -0,0 +1,681 @@
package org.jeecg.modules.biz.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.MinioUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oss.OssBootUtil;
import org.jeecg.modules.biz.constant.EntityLinkConst;
import org.jeecg.modules.biz.dto.CourseWithTeacherInfo;
import org.jeecg.modules.biz.dto.TeacherInfo;
import org.jeecg.modules.biz.service.CourseBizService;
import org.jeecg.modules.biz.service.EntityLinkBizService;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.course.mapper.CourseMapper;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import org.jeecg.modules.gen.coursecategory.mapper.CourseCategoryMapper;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import org.jeecg.modules.gen.coursesection.mapper.CourseSectionMapper;
import org.jeecg.modules.gen.coursesignup.entity.CourseSignup;
import org.jeecg.modules.gen.coursesignup.mapper.CourseSignupMapper;
import org.jeecg.modules.gen.courseteacher.entity.CourseTeacher;
import org.jeecg.modules.gen.courseteacher.mapper.CourseTeacherMapper;
import org.jeecg.modules.gen.homework.mapper.HomeworkMapper;
import org.jeecg.modules.gen.learnprogress.entity.LearnProgress;
import org.jeecg.modules.gen.learnprogress.mapper.LearnProgressMapper;
import org.jeecg.modules.gen.resource.mapper.ResourceMapper;
import org.jeecg.modules.gen.userinfo.entity.UserInfo;
import org.jeecg.modules.gen.userinfo.mapper.UserInfoMapper;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.springframework.beans.BeanUtils;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Date;
@Slf4j
@Service
public class CourseBizServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseBizService {
@Autowired
private CourseMapper courseMapper;
@Autowired
private CourseCategoryMapper courseCategoryMapper;
@Autowired
private CourseSectionMapper courseSectionMapper;
@Autowired
private EntityLinkBizService entityLinkBizService;
@Autowired
private ResourceMapper resourceMapper;
@Autowired
private CourseTeacherMapper courseTeacherMapper;
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private HomeworkMapper homeworkMapper;
@Autowired
private CourseSignupMapper courseSignupMapper;
@Autowired
private LearnProgressMapper learnProgressMapper;
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 将Map转换为JSON字符串
*/
private String toJsonString(Map<String, Object> map) {
try {
return objectMapper.writeValueAsString(map);
} catch (Exception e) {
log.error("JSON转换失败", e);
return map.toString();
}
}
@Override
public <T> List<T> getCourseSectionDetail(Integer type, String sectionId, Class<T> clazz) {
// 1. 查询章节是否存在
// 2. 根据章节类型查询entitylink表获取关联的实体id
// 3. 根据实体id查询实体表获取实体详情
// 4. 返回实体详情
// 1. 查询章节是否存在
CourseSection section = courseSectionMapper.selectById(sectionId);
if (section == null) {
throw new RuntimeException("章节不存在");
}
// 2. 根据章节类型查询entitylink表获取关联的实体id
String sourceType = EntityLinkConst.SourceType.COURSE_SECTION;
String sourceId = section.getId();
String targetType = null;
// 和数据字典对应
// 视频和资料章节的区别在于资料可能存在多份资料而视频只有一份
switch (type) {
case 0:
// 视频章节
targetType = EntityLinkConst.TargetType.RESOURCE;
break;
case 1:
// 资料章节
targetType = EntityLinkConst.TargetType.RESOURCE;
break;
case 2:
// 考试章节
targetType = EntityLinkConst.TargetType.EXAM;
break;
case 3:
// 作业章节
targetType = EntityLinkConst.TargetType.HOMEWORK;
break;
default:
break;
}
List<String> targetIds = entityLinkBizService.listTargetIds(sourceType, sourceId, targetType);
if (targetIds.isEmpty()) {
throw new RuntimeException("章节没有关联的实体");
}
// 3. 根据实体id查询实体表获取实体详情
List<T> result = new ArrayList<>();
for (String targetId : targetIds) {
switch (type) {
case 0:
// 视频章节
result.add(clazz.cast(resourceMapper.selectById(targetId)));
break;
case 1:
// 资料章节
result.add(clazz.cast(resourceMapper.selectById(targetId)));
break;
case 2:
// TODO 考试章节
break;
case 3:
// 作业章节
result.add(clazz.cast(homeworkMapper.selectById(targetId)));
break;
}
}
// 4. 返回实体详情
return result;
}
@Override
public List<CourseSection> getCourseSectionList(String courseId) {
return courseSectionMapper.selectList(new QueryWrapper<CourseSection>().eq("course_id", courseId));
}
@Override
public List<CourseCategory> getCourseCategoryList() {
return courseCategoryMapper.selectList(null);
}
@Override
public List<CourseWithTeacherInfo> getCourseList(String categoryId, String difficulty, String topic) {
QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
// 根据分类查询 - 支持多个分类ID用逗号分隔
if (!"all".equals(categoryId) && categoryId != null) {
String[] categoryIds = categoryId.split(",");
Set<String> allCourseIds = new HashSet<>();
for (String catId : categoryIds) {
catId = catId.trim();
if (!catId.isEmpty()) {
List<String> courseIds = entityLinkBizService.listTargetIds(
EntityLinkConst.SourceType.COURSE_CATEGORY, catId, EntityLinkConst.TargetType.COURSE);
allCourseIds.addAll(courseIds);
}
}
if (!allCourseIds.isEmpty()) {
queryWrapper.in("id", allCourseIds);
}
}
// 根据专题查询 - 支持多个专题值用逗号分隔
if (!"all".equals(topic) && topic != null) {
String[] topics = topic.split(",");
List<String> validTopics = new ArrayList<>();
for (String topicValue : topics) {
topicValue = topicValue.trim();
if (!topicValue.isEmpty()) {
validTopics.add(topicValue);
}
}
if (!validTopics.isEmpty()) {
queryWrapper.and(wrapper -> {
for (int i = 0; i < validTopics.size(); i++) {
String topicValue = validTopics.get(i);
if (i == 0) {
// 第一个条件直接开始
wrapper.and(subWrapper -> {
subWrapper.like("subject", topicValue + ",") // 开头匹配
.or().like("subject", "," + topicValue + ",") // 中间匹配
.or().like("subject", "," + topicValue) // 结尾匹配
.or().eq("subject", topicValue); // 单独匹配
});
} else {
// 后续条件用OR连接表示任一专题匹配即可
wrapper.or(subWrapper -> {
subWrapper.like("subject", topicValue + ",") // 开头匹配
.or().like("subject", "," + topicValue + ",") // 中间匹配
.or().like("subject", "," + topicValue) // 结尾匹配
.or().eq("subject", topicValue); // 单独匹配
});
}
}
});
}
}
// 根据难度查询 - 支持多个难度值用逗号分隔
if (!"all".equals(difficulty) && difficulty != null) {
String[] difficulties = difficulty.split(",");
List<String> difficultyList = new ArrayList<>();
for (String diff : difficulties) {
diff = diff.trim();
if (!diff.isEmpty()) {
difficultyList.add(diff);
}
}
if (!difficultyList.isEmpty()) {
queryWrapper.in("difficulty", difficultyList);
}
}
List<Course> courseList = courseMapper.selectList(queryWrapper);
// 构建包含讲师信息的课程列表
List<CourseWithTeacherInfo> result = new ArrayList<>();
for (Course course : courseList) {
CourseWithTeacherInfo courseWithTeacher = new CourseWithTeacherInfo();
// 复制课程基本信息
BeanUtils.copyProperties(course, courseWithTeacher);
// 获取讲师信息
List<TeacherInfo> teacherList = getCourseTeacherList(course.getId());
courseWithTeacher.setTeacherList(teacherList);
result.add(courseWithTeacher);
}
return result;
}
@Override
public String uploadHls(MultipartFile file, HttpServletRequest request) throws Exception {
// 读取上传类型header 优先
String headerUploadType = request.getHeader("uploadType");
String configUploadType = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("jeecg.uploadType", "minio");
String uploadType = (headerUploadType != null && headerUploadType.trim().length() > 0) ? headerUploadType : configUploadType;
// 1) 保存临时原始视频
String uuid = UUID.randomUUID().toString();
String tmpRoot = System.getProperty("java.io.tmpdir");
Path tmpVideoDir = Path.of(tmpRoot, "jeecg", "video", uuid);
Path hlsDir = Path.of(tmpRoot, "jeecg", "hls", uuid);
Files.createDirectories(tmpVideoDir);
Files.createDirectories(hlsDir);
String original = CommonUtils.getFileName(Objects.requireNonNull(file.getOriginalFilename()));
Path tmpVideoFile = tmpVideoDir.resolve(original);
Files.copy(file.getInputStream(), tmpVideoFile, StandardCopyOption.REPLACE_EXISTING);
// 2) ffmpeg 切片
Path m3u8Path = hlsDir.resolve(uuid + ".m3u8");
List<String> cmd = Arrays.asList(
"ffmpeg", "-i", tmpVideoFile.toString(),
"-c:v", "libx264", "-c:a", "aac",
"-hls_time", "10", "-hls_playlist_type", "vod",
m3u8Path.toString());
Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
boolean ok = p.waitFor(10, TimeUnit.MINUTES) && p.exitValue() == 0;
if (!ok) {
deleteQuietly(hlsDir.toFile());
deleteQuietly(tmpVideoDir.toFile());
throw new RuntimeException("ffmpeg切片超时");
}
// 3) 上传切片
String m3u8Url = "";
String base = "video/hls/" + uuid;
try (Stream<Path> paths = Files.list(hlsDir)) {
for (Path f : (Iterable<Path>) paths::iterator) {
if (!Files.isRegularFile(f)) continue;
String rel = base + "/" + f.getFileName().toString();
try (InputStream in = Files.newInputStream(f)) {
if ("minio".equals(uploadType)) {
String tmpUrl = MinioUtil.upload(in, rel);
if (f.getFileName().toString().endsWith(".m3u8")) {
m3u8Url = tmpUrl;
}
} else if ("alioss".equals(uploadType)) {
OssBootUtil.upload(in, rel);
if (f.getFileName().toString().endsWith(".m3u8")) {
m3u8Url = rel; // 可在网关拼域名
}
} else {
String uploadpath = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("jeecg.path.upload");
Path target = Path.of(uploadpath, rel);
Files.createDirectories(target.getParent());
Files.copy(f, target, StandardCopyOption.REPLACE_EXISTING);
if (f.getFileName().toString().endsWith(".m3u8")) {
m3u8Url = rel; // local 返回相对路径
}
}
}
}
} finally {
deleteQuietly(hlsDir.toFile());
deleteQuietly(tmpVideoDir.toFile());
}
return m3u8Url;
}
/** 删除临时目录文件 */
private static void deleteQuietly(File file) {
try {
if (file == null || !file.exists()) return;
if (file.isDirectory()) {
File[] children = file.listFiles();
if (children != null) {
for (File c : children) deleteQuietly(c);
}
}
file.delete();
} catch (Exception ignored) {}
}
@Override
public List<TeacherInfo> getCourseTeacherList(String courseId) {
List<CourseTeacher> list = courseTeacherMapper.selectList(new QueryWrapper<CourseTeacher>().eq("course_id", courseId));
List<TeacherInfo> result = new ArrayList<>();
for (CourseTeacher item : list) {
UserInfo userInfo = userInfoMapper.selectOne(new QueryWrapper<UserInfo>().eq("user_id", item.getTeacherId()));
SysUser sysUser = sysUserMapper.selectById(item.getTeacherId());
TeacherInfo teacherInfo = new TeacherInfo();
teacherInfo.setId(item.getTeacherId());
teacherInfo.setName(sysUser.getRealname());
teacherInfo.setAvatar(sysUser.getAvatar());
teacherInfo.setTitle(userInfo.getTitle());
teacherInfo.setTag(userInfo.getTag());
teacherInfo.setSortOrder(userInfo.getSortOrder());
result.add(teacherInfo);
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String enrollCourse(String courseId, String userId) {
// 1. 参数校验
if (courseId == null || courseId.trim().isEmpty()) {
throw new RuntimeException("课程ID不能为空");
}
if (userId == null || userId.trim().isEmpty()) {
throw new RuntimeException("用户ID不能为空");
}
// 2. 查询课程是否存在
Course course = courseMapper.selectById(courseId);
if (course == null) {
throw new RuntimeException("课程不存在");
}
// 3. 检查用户是否已报名
QueryWrapper<CourseSignup> signupQuery = new QueryWrapper<>();
signupQuery.eq("user_id", userId).eq("course_id", courseId);
CourseSignup existingSignup = courseSignupMapper.selectOne(signupQuery);
if (existingSignup != null) {
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("code", "already_enrolled");
result.put("message", "用户已经报名该课程");
return toJsonString(result);
}
// 4. 检查课程是否可以报名
if (course.getStatus() != null && course.getStatus() != 1) {
throw new RuntimeException("课程当前状态不允许报名");
}
// 5. 检查报名人数是否已满
if (course.getMaxEnroll() != null && course.getEnrollCount() != null) {
if (course.getEnrollCount() >= course.getMaxEnroll()) {
throw new RuntimeException("报名人数已满");
}
}
// 6. 创建报名记录
CourseSignup signup = new CourseSignup();
signup.setUserId(userId);
signup.setCourseId(courseId);
signup.setCreateTime(new Date());
signup.setCreateBy(userId);
int insertResult = courseSignupMapper.insert(signup);
if (insertResult <= 0) {
throw new RuntimeException("报名失败");
}
// 7. 更新课程报名人数
int currentEnrollCount = course.getEnrollCount() == null ? 0 : course.getEnrollCount();
course.setEnrollCount(currentEnrollCount + 1);
courseMapper.updateById(course);
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("code", "success");
result.put("message", "报名成功");
return toJsonString(result);
}
@Override
public boolean isEnrolled(String courseId, String userId) {
QueryWrapper<CourseSignup> signupQuery = new QueryWrapper<>();
signupQuery.eq("user_id", userId).eq("course_id", courseId);
CourseSignup existingSignup = courseSignupMapper.selectOne(signupQuery);
return existingSignup != null;
}
@Override
@Transactional
public Map<String, Object> addStudents(String courseId, String ids, LoginUser teacher) {
// 1. 参数校验
if (courseId == null || courseId.trim().isEmpty()) {
throw new RuntimeException("课程ID不能为空");
}
if (ids == null || ids.isEmpty()) {
throw new RuntimeException("学生ID列表不能为空");
}
if (teacher == null || teacher.getId() == null) {
throw new RuntimeException("教师信息不能为空");
}
// 2. 查询课程是否存在
Course course = courseMapper.selectById(courseId);
if (course == null) {
throw new RuntimeException("课程不存在");
}
// 3. 权限校验 - 检查当前登录用户是否是课程的创建人
if (!teacher.getUsername().equals(course.getCreateBy())) {
throw new RuntimeException("只有课程创建者才能添加学生");
}
// 4. 过滤有效的学生ID
List<String> validStudentIds = new ArrayList<>();
for (String studentId : ids.split(",")) {
if (studentId != null && !studentId.trim().isEmpty()) {
validStudentIds.add(studentId.trim());
}
}
if (validStudentIds.isEmpty()) {
throw new RuntimeException("没有有效的学生ID");
}
// 5. 检查哪些学生已经报名
QueryWrapper<CourseSignup> existingQuery = new QueryWrapper<>();
existingQuery.eq("course_id", courseId).in("user_id", validStudentIds);
List<CourseSignup> existingSignups = courseSignupMapper.selectList(existingQuery);
Set<String> alreadyEnrolledIds = new HashSet<>();
for (CourseSignup signup : existingSignups) {
alreadyEnrolledIds.add(signup.getUserId());
}
// 6. 过滤出需要新增的学生ID
List<String> newStudentIds = new ArrayList<>();
for (String studentId : validStudentIds) {
if (!alreadyEnrolledIds.contains(studentId)) {
newStudentIds.add(studentId);
}
}
if (newStudentIds.isEmpty()) {
Map<String, Object> result = new HashMap<>();
result.put("success", false);
result.put("code", "all_already_enrolled");
result.put("message", "所有学生都已经报名");
result.put("addedCount", 0);
result.put("alreadyEnrolledCount", alreadyEnrolledIds.size());
return result;
}
// 7. 检查报名人数限制
int currentEnrollCount = course.getEnrollCount() == null ? 0 : course.getEnrollCount();
if (course.getMaxEnroll() != null) {
if (currentEnrollCount + newStudentIds.size() > course.getMaxEnroll()) {
throw new RuntimeException("添加学生后将超过最大报名人数限制,当前:" + currentEnrollCount + ",最大:" + course.getMaxEnroll() + ",新增:" + newStudentIds.size());
}
}
// 8. 批量创建报名记录
List<CourseSignup> newSignups = new ArrayList<>();
Date now = new Date();
for (String studentId : newStudentIds) {
CourseSignup signup = new CourseSignup();
signup.setUserId(studentId);
signup.setCourseId(courseId);
signup.setCreateTime(now);
signup.setCreateBy(teacher.getId());
newSignups.add(signup);
}
// 9. 批量插入报名记录
for (CourseSignup signup : newSignups) {
int insertResult = courseSignupMapper.insert(signup);
if (insertResult <= 0) {
throw new RuntimeException("插入报名记录失败学生ID: " + signup.getUserId());
}
}
// 10. 更新课程报名人数
course.setEnrollCount(currentEnrollCount + newStudentIds.size());
courseMapper.updateById(course);
// 11. 返回结果
Map<String, Object> result = new HashMap<>();
if (alreadyEnrolledIds.isEmpty()) {
result.put("success", true);
result.put("code", "success");
result.put("message", "所有学生都成功添加");
result.put("addedCount", newStudentIds.size());
result.put("alreadyEnrolledCount", 0);
} else {
result.put("success", true);
result.put("code", "partial_success");
result.put("message", "部分学生添加成功,部分学生已经报名");
result.put("addedCount", newStudentIds.size());
result.put("alreadyEnrolledCount", alreadyEnrolledIds.size());
}
return result;
}
@Override
public Map<String, Object> getCourseProgress(String courseId, String userId) {
// 1. 参数校验
if (courseId == null || courseId.trim().isEmpty()) {
throw new RuntimeException("课程ID不能为空");
}
if (userId == null || userId.trim().isEmpty()) {
throw new RuntimeException("用户ID不能为空");
}
// 2. 分别查询视频考试作业章节
List<CourseSection> videoSections = getCourseSectionsByType(courseId, 0); // 视频
List<CourseSection> examSections = getCourseSectionsByType(courseId, 2); // 考试
List<CourseSection> homeworkSections = getCourseSectionsByType(courseId, 3); // 作业
// 3. 分别查询各类型章节的完成情况
int videoCompleted = getCompletedSectionCount(courseId, userId, videoSections);
int examCompleted = getCompletedSectionCount(courseId, userId, examSections);
int homeworkCompleted = getCompletedSectionCount(courseId, userId, homeworkSections);
// 4. 计算各类型进度百分比
int videoProgress = calculateProgress(videoCompleted, videoSections.size());
int examProgress = calculateProgress(examCompleted, examSections.size());
int homeworkProgress = calculateProgress(homeworkCompleted, homeworkSections.size());
// 5. 计算总进度
int totalSections = videoSections.size() + examSections.size() + homeworkSections.size();
int totalCompleted = videoCompleted + examCompleted + homeworkCompleted;
int totalProgress = calculateProgress(totalCompleted, totalSections);
// 6. 构建返回结果
Map<String, Object> result = new HashMap<>();
// 视频进度
Map<String, Object> videoInfo = new HashMap<>();
videoInfo.put("total", videoSections.size());
videoInfo.put("completed", videoCompleted);
videoInfo.put("progress", videoProgress);
result.put("video", videoInfo);
// 考试进度
Map<String, Object> examInfo = new HashMap<>();
examInfo.put("total", examSections.size());
examInfo.put("completed", examCompleted);
examInfo.put("progress", examProgress);
result.put("exam", examInfo);
// 作业进度
Map<String, Object> homeworkInfo = new HashMap<>();
homeworkInfo.put("total", homeworkSections.size());
homeworkInfo.put("completed", homeworkCompleted);
homeworkInfo.put("progress", homeworkProgress);
result.put("homework", homeworkInfo);
// 总进度
Map<String, Object> totalInfo = new HashMap<>();
totalInfo.put("total", totalSections);
totalInfo.put("completed", totalCompleted);
totalInfo.put("progress", totalProgress);
result.put("total", totalInfo);
return result;
}
/**
* 根据类型查询课程章节
*/
private List<CourseSection> getCourseSectionsByType(String courseId, Integer type) {
QueryWrapper<CourseSection> query = new QueryWrapper<>();
query.eq("course_id", courseId).eq("type", type).eq("level", 2);
return courseSectionMapper.selectList(query);
}
/**
* 获取已完成的章节数量
*/
private int getCompletedSectionCount(String courseId, String userId, List<CourseSection> sections) {
if (sections.isEmpty()) {
return 0;
}
List<String> sectionIds = sections.stream()
.map(CourseSection::getId)
.collect(Collectors.toList());
QueryWrapper<LearnProgress> progressQuery = new QueryWrapper<>();
progressQuery.eq("user_id", userId)
.eq("course_id", courseId)
.in("section_id", sectionIds)
.eq("status", 2); // status=2表示学习完成
return Math.toIntExact(learnProgressMapper.selectCount(progressQuery));
}
/**
* 计算进度百分比
*/
private int calculateProgress(int completed, int total) {
if (total == 0) {
return 100; // 如果没有章节认为已完成
}
return Math.round((float) completed / total * 100);
}
}

View File

@ -0,0 +1,36 @@
package org.jeecg.modules.biz.service.impl;
import org.jeecg.modules.biz.service.EntityLinkBizService;
import org.jeecg.modules.gen.entitylink.entity.EntityLink;
import org.jeecg.modules.gen.entitylink.mapper.EntityLinkMapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class EntityLinkBizServiceImpl extends ServiceImpl<EntityLinkMapper, EntityLink> implements EntityLinkBizService {
@Override
public List<String> listTargetIds(String sourceType, String sourceId, String targetType) {
LambdaQueryWrapper<EntityLink> qw = new LambdaQueryWrapper<>();
qw.eq(EntityLink::getSourceType, sourceType)
.eq(EntityLink::getSourceId, sourceId)
.eq(EntityLink::getTargetType, targetType)
.select(EntityLink::getTargetId);
return this.list(qw).stream()
.map(EntityLink::getTargetId)
.distinct()
.collect(Collectors.toList());
}
@Override
public void save(String sourceType, String sourceId, String targetType, String targetId) {
EntityLink entityLink = new EntityLink();
entityLink.setSourceType(sourceType);
entityLink.setSourceId(sourceId);
entityLink.setTargetType(targetType);
entityLink.setTargetId(targetId);
this.save(entityLink);
}
}

View File

@ -0,0 +1,36 @@
package org.jeecg.modules.biz.service.impl;
import org.jeecg.modules.biz.constant.EntityLinkConst;
import org.jeecg.modules.biz.service.EntityLinkBizService;
import org.jeecg.modules.biz.service.IHomeworkBizService;
import org.jeecg.modules.gen.homework.entity.Homework;
import org.jeecg.modules.gen.homework.mapper.HomeworkMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class HomeworkBizServiceImpl extends ServiceImpl<HomeworkMapper, Homework> implements IHomeworkBizService {
@Autowired
private EntityLinkBizService entityLinkBizService;
@Override
public List<Homework> listByCourseId(String courseId) {
List<String> homeworkIds = entityLinkBizService.listTargetIds(EntityLinkConst.SourceType.COURSE, courseId, EntityLinkConst.TargetType.HOMEWORK);
if (homeworkIds.size() > 0) {
return this.listByIds(homeworkIds);
} else {
return new ArrayList<>();
}
}
}

View File

@ -0,0 +1,324 @@
package org.jeecg.modules.biz.service.impl;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.MinioUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oss.OssBootUtil;
import org.jeecg.modules.biz.service.ResourceBizService;
import org.jeecg.modules.gen.resource.mapper.ResourceMapper;
import org.jeecg.modules.gen.resource.entity.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@Slf4j
@Service
public class ResourceBizServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements ResourceBizService {
/**
* 视频清晰度配置
*/
@Data
@AllArgsConstructor
public static class VideoQuality {
private String name; // 清晰度名称
private String outputDir; // 输出目录
private int width; // 宽度
private int height; // 高度
private String bitrate; // 视频比特率
private String audioRate; // 音频比特率
}
// 预定义的清晰度配置
private static final List<VideoQuality> QUALITY_CONFIGS = Arrays.asList(
new VideoQuality("480p", "480p", 854, 480, "1000k", "96k"),
new VideoQuality("720p", "720p", 1280, 720, "2500k", "128k"),
new VideoQuality("1080p", "1080p", 1920, 1080, "5000k", "192k")
);
private static final int SEGMENT_TIME = 10; // HLS切片时长
private static final ExecutorService executorService = Executors.newFixedThreadPool(3);
@Override
public Map<String, String> uploadHls(MultipartFile file, HttpServletRequest request) throws Exception {
// 读取上传类型
String configUploadType = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("jeecg.uploadType", "minio");
String uploadType = configUploadType;
// 1) 保存临时原始视频
String uuid = UUID.randomUUID().toString();
String tmpRoot = System.getProperty("java.io.tmpdir");
Path tmpVideoDir = Path.of(tmpRoot, "jeecg", "video", uuid);
Path hlsBaseDir = Path.of(tmpRoot, "jeecg", "hls", uuid);
Files.createDirectories(tmpVideoDir);
Files.createDirectories(hlsBaseDir);
String original = CommonUtils.getFileName(Objects.requireNonNull(file.getOriginalFilename()));
Path tmpVideoFile = tmpVideoDir.resolve(original);
Files.copy(file.getInputStream(), tmpVideoFile, StandardCopyOption.REPLACE_EXISTING);
log.info("开始多清晰度视频处理,文件: {}", original);
try {
// 2) 并行处理多个清晰度
List<CompletableFuture<Map<String, String>>> futures = new ArrayList<>();
for (VideoQuality quality : QUALITY_CONFIGS) {
CompletableFuture<Map<String, String>> future = CompletableFuture.supplyAsync(() -> {
try {
return processVideoQuality(tmpVideoFile, hlsBaseDir, quality, uploadType, uuid);
} catch (Exception e) {
log.error("处理{}清晰度失败", quality.getName(), e);
throw new RuntimeException("处理" + quality.getName() + "清晰度失败: " + e.getMessage());
}
}, executorService);
futures.add(future);
}
// 3) 等待所有清晰度处理完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0])
);
// 设置超时时间为30分钟
allFutures.get(30, TimeUnit.MINUTES);
// 4) 收集结果 - 各清晰度的index.m3u8地址
Map<String, String> qualityUrls = new HashMap<>();
for (CompletableFuture<Map<String, String>> future : futures) {
qualityUrls.putAll(future.get());
}
log.info("多清晰度视频处理完成,各清晰度地址: {}", qualityUrls);
return qualityUrls;
} finally {
// 清理临时文件
deleteQuietly(hlsBaseDir.toFile());
deleteQuietly(tmpVideoDir.toFile());
}
}
/**
* 处理单个清晰度的视频切片
*/
private Map<String, String> processVideoQuality(Path inputFile, Path hlsBaseDir, VideoQuality quality, String uploadType, String uuid) throws Exception {
log.info("开始处理 {} 清晰度...", quality.getName());
// 创建清晰度输出目录
Path outputDir = hlsBaseDir.resolve(quality.getOutputDir());
Files.createDirectories(outputDir);
Path playlistPath = outputDir.resolve("index.m3u8");
// 构建FFmpeg命令 - 参考Go代码
List<String> args = Arrays.asList(
"ffmpeg", "-i", inputFile.toString(),
"-vf", String.format("scale=%d:%d", quality.getWidth(), quality.getHeight()),
"-c:v", "libx264",
"-b:v", quality.getBitrate(),
"-c:a", "aac",
"-b:a", quality.getAudioRate(),
"-hls_time", String.valueOf(SEGMENT_TIME),
"-hls_playlist_type", "vod",
"-hls_segment_filename", outputDir.resolve("segment%d.ts").toString(),
"-y", // 覆盖已存在的文件
playlistPath.toString()
);
// 执行FFmpeg并处理日志
executeFFmpegWithLogging(args, quality.getName());
log.info("{} 清晰度处理完成", quality.getName());
// 上传切片文件
return uploadQualityFiles(outputDir, quality, uploadType, uuid);
}
/**
* 上传单个清晰度的所有文件
*/
private Map<String, String> uploadQualityFiles(Path outputDir, VideoQuality quality, String uploadType, String uuid) throws Exception {
Map<String, String> urls = new HashMap<>();
String basePrefix = "video/hls/" + uuid + "/" + quality.getOutputDir();
String m3u8Url = "";
try (Stream<Path> paths = Files.list(outputDir)) {
for (Path file : (Iterable<Path>) paths::iterator) {
if (!Files.isRegularFile(file)) continue;
String fileName = file.getFileName().toString();
String relativePath = basePrefix + "/" + fileName;
try (InputStream in = Files.newInputStream(file)) {
String fileUrl = "";
if ("minio".equals(uploadType)) {
fileUrl = MinioUtil.upload(in, relativePath);
} else if ("alioss".equals(uploadType)) {
OssBootUtil.upload(in, relativePath);
fileUrl = relativePath; // 可在网关拼域名
} else {
// 本地存储
String uploadpath = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("jeecg.path.upload");
Path target = Path.of(uploadpath, relativePath);
Files.createDirectories(target.getParent());
Files.copy(file, target, StandardCopyOption.REPLACE_EXISTING);
fileUrl = relativePath;
}
if (fileName.endsWith(".m3u8")) {
m3u8Url = fileUrl;
}
}
}
}
urls.put(quality.getName(), m3u8Url);
return urls;
}
/**
* 执行FFmpeg命令并处理日志输出
*/
private void executeFFmpegWithLogging(List<String> args, String qualityName) throws Exception {
// 打印FFmpeg命令
log.info("执行FFmpeg命令[{}]: {}", qualityName, String.join(" ", args));
ProcessBuilder pb = new ProcessBuilder(args);
pb.redirectErrorStream(true); // 将错误输出重定向到标准输出
Process process = pb.start();
// 使用单独的线程来读取FFmpeg输出避免阻塞
StringBuilder ffmpegOutput = new StringBuilder();
Thread logThread = new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
synchronized (ffmpegOutput) {
ffmpegOutput.append(line).append("\n");
}
// 输出详细日志到DEBUG级别
log.debug("FFmpeg[{}]: {}", qualityName, line);
// 过滤并输出关键进度信息
if (line.contains("frame=") && line.contains("time=")) {
// 提取进度信息
String progressInfo = extractProgressInfo(line);
if (progressInfo != null) {
log.info("FFmpeg进度[{}]: {}", qualityName, progressInfo);
}
}
// 输出警告和错误信息
if (line.toLowerCase().contains("warning") || line.toLowerCase().contains("error")) {
log.warn("FFmpeg[{}]: {}", qualityName, line);
}
// 输出关键状态信息
if (line.contains("Stream mapping:") || line.contains("Press [q] to stop") ||
line.contains("video:") || line.contains("audio:")) {
log.info("FFmpeg[{}]: {}", qualityName, line);
}
}
} catch (Exception e) {
log.error("读取FFmpeg输出时发生错误[{}]", qualityName, e);
}
});
logThread.setDaemon(true);
logThread.start();
// 等待进程完成
boolean finished = process.waitFor(15, TimeUnit.MINUTES);
int exitCode = process.exitValue();
// 等待日志线程完成
logThread.join(5000); // 最多等待5秒
if (!finished || exitCode != 0) {
synchronized (ffmpegOutput) {
log.error("FFmpeg处理[{}]失败,退出码: {}", qualityName, exitCode);
log.error("FFmpeg完整输出[{}]:\n{}", qualityName, ffmpegOutput.toString());
}
throw new RuntimeException(String.format("FFmpeg处理%s失败退出码: %d", qualityName, exitCode));
}
log.info("FFmpeg处理[{}]成功完成", qualityName);
}
/**
* 从FFmpeg输出行中提取进度信息
*/
private String extractProgressInfo(String line) {
try {
// FFmpeg进度行格式示例
// frame= 1234 fps= 25 q=23.0 size= 12345kB time=00:01:23.45 bitrate=1234.5kbits/s speed=1.23x
if (line.contains("time=") && line.contains("bitrate=")) {
// 提取时间和比特率信息
String time = "";
String bitrate = "";
String speed = "";
String frame = "";
String[] parts = line.split("\\s+");
for (String part : parts) {
if (part.startsWith("time=")) {
time = part.substring(5);
} else if (part.startsWith("bitrate=")) {
bitrate = part.substring(8);
} else if (part.startsWith("speed=")) {
speed = part.substring(6);
} else if (part.startsWith("frame=")) {
frame = part.substring(6);
}
}
if (!time.isEmpty()) {
return String.format("frame=%s time=%s bitrate=%s speed=%s", frame, time, bitrate, speed);
}
}
} catch (Exception e) {
// 解析失败时忽略返回原始行
return line.trim();
}
return null;
}
/** 删除临时目录文件 */
private static void deleteQuietly(File file) {
try {
if (file == null || !file.exists()) return;
if (file.isDirectory()) {
File[] children = file.listFiles();
if (children != null) {
for (File c : children) deleteQuietly(c);
}
}
file.delete();
} catch (Exception ignored) {}
}
}

View File

@ -0,0 +1,93 @@
package org.jeecg.modules.biz.service.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.jeecg.modules.biz.constant.EntityLinkConst;
import org.jeecg.modules.biz.dto.TeacherInfo;
import org.jeecg.modules.biz.service.EntityLinkBizService;
import org.jeecg.modules.biz.service.UserBizService;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.course.mapper.CourseMapper;
import org.jeecg.modules.gen.courseteacher.entity.CourseTeacher;
import org.jeecg.modules.gen.courseteacher.mapper.CourseTeacherMapper;
import org.jeecg.modules.gen.entitylink.mapper.EntityLinkMapper;
import org.jeecg.modules.gen.userinfo.entity.UserInfo;
import org.jeecg.modules.gen.userinfo.mapper.UserInfoMapper;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UserBizServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserBizService {
@Autowired
private CourseMapper courseMapper;
@Autowired
private EntityLinkMapper entityLinkMapper;
@Autowired
private EntityLinkBizService entityLinkBizService;
@Autowired
private CourseTeacherMapper courseTeacherMapper;
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
private SysUserMapper sysUserMapper;
@Override
public List<TeacherInfo> queryAllTeachers(String categoryId) {
// categoryId为all则查询全部
// TODO 存入redis缓存
// 1 根据课程分类查询该分类下的课程; all 则查询全部课程
// 2 遍历课程根据课程id查询该课程的授课教师
// 3 将授课教师信息封装成TeacherInfo对象
// 4 返回授课教师列表去重
// 1 根据课程分类查询该分类下的课程
List<String> courseIds;
if ("all".equals(categoryId)) {
// 查询全部课程
List<Course> courseList = courseMapper.selectList(null);
courseIds = courseList.stream().map(Course::getId).collect(Collectors.toList());
} else {
courseIds = entityLinkBizService.listTargetIds(EntityLinkConst.SourceType.COURSE_CATEGORY, categoryId, EntityLinkConst.TargetType.COURSE);
}
Set<String> teacherIds = new HashSet<>();
List<TeacherInfo> result = new ArrayList<>();
for (String courseId : courseIds) {
// 2 根据课程id查询该课程的授课教师
List<CourseTeacher> courseTeachers = courseTeacherMapper.selectList(new LambdaQueryWrapper<CourseTeacher>().eq(CourseTeacher::getCourseId, courseId));
// 3 将授课教师信息封装成TeacherInfo对象
for (CourseTeacher courseTeacher : courseTeachers) {
// 4 将授课教师信息封装成TeacherInfo对象去重
UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, courseTeacher.getTeacherId()));
SysUser sysUser = sysUserMapper.selectById(courseTeacher.getTeacherId());
TeacherInfo teacherInfo = new TeacherInfo();
teacherInfo.setId(courseTeacher.getTeacherId());
teacherInfo.setName(sysUser.getRealname());
teacherInfo.setAvatar(sysUser.getAvatar());
teacherInfo.setTitle(userInfo.getTitle());
teacherInfo.setTag(userInfo.getTag());
teacherInfo.setSortOrder(userInfo.getSortOrder());
if (!teacherIds.contains(courseTeacher.getTeacherId())) {
result.add(teacherInfo);
teacherIds.add(courseTeacher.getTeacherId());
}
}
}
return result;
}
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.activity.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.activity.entity.Activity;
import org.jeecg.modules.gen.activity.service.IActivityService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 活动
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
@Tag(name="活动")
@RestController
@RequestMapping("/gen/activity/activity")
@Slf4j
public class ActivityController extends JeecgController<Activity, IActivityService> {
@Autowired
private IActivityService activityService;
/**
* 分页列表查询
*
* @param activity
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "活动-分页列表查询")
@Operation(summary="活动-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<Activity>> queryPageList(Activity activity,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<Activity> queryWrapper = QueryGenerator.initQueryWrapper(activity, req.getParameterMap());
Page<Activity> page = new Page<Activity>(pageNo, pageSize);
IPage<Activity> pageList = activityService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param activity
* @return
*/
@AutoLog(value = "活动-添加")
@Operation(summary="活动-添加")
@RequiresPermissions("gen.activity:activity:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody Activity activity) {
activityService.save(activity);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param activity
* @return
*/
@AutoLog(value = "活动-编辑")
@Operation(summary="活动-编辑")
@RequiresPermissions("gen.activity:activity:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody Activity activity) {
activityService.updateById(activity);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "活动-通过id删除")
@Operation(summary="活动-通过id删除")
@RequiresPermissions("gen.activity:activity:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
activityService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "活动-批量删除")
@Operation(summary="活动-批量删除")
@RequiresPermissions("gen.activity:activity:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.activityService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "活动-通过id查询")
@Operation(summary="活动-通过id查询")
@GetMapping(value = "/queryById")
public Result<Activity> queryById(@RequestParam(name="id",required=true) String id) {
Activity activity = activityService.getById(id);
if(activity==null) {
return Result.error("未找到对应数据");
}
return Result.OK(activity);
}
/**
* 导出excel
*
* @param request
* @param activity
*/
@RequiresPermissions("gen.activity:activity:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, Activity activity) {
return super.exportXls(request, activity, Activity.class, "活动");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.activity:activity:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, Activity.class);
}
}

View File

@ -0,0 +1,105 @@
package org.jeecg.modules.gen.activity.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 活动
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
@Data
@TableName("activity")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="活动")
public class Activity implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**标题*/
@Excel(name = "标题", width = 15)
@Schema(description = "标题")
private java.lang.String title;
/**介绍*/
@Excel(name = "介绍", width = 15)
@Schema(description = "介绍")
private java.lang.String introduction;
/**说明图片*/
@Excel(name = "说明图片", width = 15)
@Schema(description = "说明图片")
private java.lang.String imgs;
/**头图*/
@Excel(name = "头图", width = 15)
@Schema(description = "头图")
private java.lang.String banner;
/**介绍视频*/
@Excel(name = "介绍视频", width = 15)
@Schema(description = "介绍视频")
private java.lang.String video;
/**报名人数上限*/
@Excel(name = "报名人数上限", width = 15)
@Schema(description = "报名人数上限")
private java.lang.Integer maxNum;
/**开始时间*/
@Excel(name = "开始时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "开始时间")
private java.util.Date startTime;
/**结束时间*/
@Excel(name = "结束时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "结束时间")
private java.util.Date endTime;
/**扩展字段*/
@Excel(name = "扩展字段", width = 15)
@Schema(description = "扩展字段")
private java.lang.String extra;
/**附件*/
@Excel(name = "附件", width = 15)
@Schema(description = "附件")
private java.lang.String attachment;
/**状态*/
@Excel(name = "状态", width = 15, dicCode = "course_status")
@Dict(dicCode = "course_status")
@Schema(description = "状态")
private java.lang.String status;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.activity.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.activity.entity.Activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 活动
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
public interface ActivityMapper extends BaseMapper<Activity> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.activity.mapper.ActivityMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.activity.service;
import org.jeecg.modules.gen.activity.entity.Activity;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 活动
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
public interface IActivityService extends IService<Activity> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.activity.service.impl;
import org.jeecg.modules.gen.activity.entity.Activity;
import org.jeecg.modules.gen.activity.mapper.ActivityMapper;
import org.jeecg.modules.gen.activity.service.IActivityService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 活动
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
@Service
public class ActivityServiceImpl extends ServiceImpl<ActivityMapper, Activity> implements IActivityService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.activitysignup.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.activitysignup.entity.ActivitySignup;
import org.jeecg.modules.gen.activitysignup.service.IActivitySignupService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 活动报名
* @Author: jeecg-boot
* @Date: 2025-08-21
* @Version: V1.0
*/
@Tag(name="活动报名")
@RestController
@RequestMapping("/gen/activitysignup/activitySignup")
@Slf4j
public class ActivitySignupController extends JeecgController<ActivitySignup, IActivitySignupService> {
@Autowired
private IActivitySignupService activitySignupService;
/**
* 分页列表查询
*
* @param activitySignup
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "活动报名-分页列表查询")
@Operation(summary="活动报名-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<ActivitySignup>> queryPageList(ActivitySignup activitySignup,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<ActivitySignup> queryWrapper = QueryGenerator.initQueryWrapper(activitySignup, req.getParameterMap());
Page<ActivitySignup> page = new Page<ActivitySignup>(pageNo, pageSize);
IPage<ActivitySignup> pageList = activitySignupService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param activitySignup
* @return
*/
@AutoLog(value = "活动报名-添加")
@Operation(summary="活动报名-添加")
@RequiresPermissions("gen.activitysignup:activity_signup:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ActivitySignup activitySignup) {
activitySignupService.save(activitySignup);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param activitySignup
* @return
*/
@AutoLog(value = "活动报名-编辑")
@Operation(summary="活动报名-编辑")
@RequiresPermissions("gen.activitysignup:activity_signup:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody ActivitySignup activitySignup) {
activitySignupService.updateById(activitySignup);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "活动报名-通过id删除")
@Operation(summary="活动报名-通过id删除")
@RequiresPermissions("gen.activitysignup:activity_signup:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
activitySignupService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "活动报名-批量删除")
@Operation(summary="活动报名-批量删除")
@RequiresPermissions("gen.activitysignup:activity_signup:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.activitySignupService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "活动报名-通过id查询")
@Operation(summary="活动报名-通过id查询")
@GetMapping(value = "/queryById")
public Result<ActivitySignup> queryById(@RequestParam(name="id",required=true) String id) {
ActivitySignup activitySignup = activitySignupService.getById(id);
if(activitySignup==null) {
return Result.error("未找到对应数据");
}
return Result.OK(activitySignup);
}
/**
* 导出excel
*
* @param request
* @param activitySignup
*/
@RequiresPermissions("gen.activitysignup:activity_signup:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ActivitySignup activitySignup) {
return super.exportXls(request, activitySignup, ActivitySignup.class, "活动报名");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.activitysignup:activity_signup:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, ActivitySignup.class);
}
}

View File

@ -0,0 +1,80 @@
package org.jeecg.modules.gen.activitysignup.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 活动报名
* @Author: jeecg-boot
* @Date: 2025-08-21
* @Version: V1.0
*/
@Data
@TableName("activity_signup")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="活动报名")
public class ActivitySignup implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**姓名*/
@Excel(name = "姓名", width = 15)
@Schema(description = "姓名")
private java.lang.String name;
/**年龄*/
@Excel(name = "年龄", width = 15)
@Schema(description = "年龄")
private java.lang.String age;
/**手机号*/
@Excel(name = "手机号", width = 15)
@Schema(description = "手机号")
private java.lang.String phone;
/**邮箱*/
@Excel(name = "邮箱", width = 15)
@Schema(description = "邮箱")
private java.lang.String email;
/**扩展字段*/
@Excel(name = "扩展字段", width = 15)
@Schema(description = "扩展字段")
private java.lang.String extra;
/**附件*/
@Excel(name = "附件", width = 15)
@Schema(description = "附件")
private java.lang.String attachment;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.activitysignup.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.activitysignup.entity.ActivitySignup;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 活动报名
* @Author: jeecg-boot
* @Date: 2025-08-21
* @Version: V1.0
*/
public interface ActivitySignupMapper extends BaseMapper<ActivitySignup> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.activitysignup.mapper.ActivitySignupMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.activitysignup.service;
import org.jeecg.modules.gen.activitysignup.entity.ActivitySignup;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 活动报名
* @Author: jeecg-boot
* @Date: 2025-08-21
* @Version: V1.0
*/
public interface IActivitySignupService extends IService<ActivitySignup> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.activitysignup.service.impl;
import org.jeecg.modules.gen.activitysignup.entity.ActivitySignup;
import org.jeecg.modules.gen.activitysignup.mapper.ActivitySignupMapper;
import org.jeecg.modules.gen.activitysignup.service.IActivitySignupService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 活动报名
* @Author: jeecg-boot
* @Date: 2025-08-21
* @Version: V1.0
*/
@Service
public class ActivitySignupServiceImpl extends ServiceImpl<ActivitySignupMapper, ActivitySignup> implements IActivitySignupService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.aioltag.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.aioltag.entity.AiolTag;
import org.jeecg.modules.gen.aioltag.service.IAiolTagService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 标签
* @Author: jeecg-boot
* @Date: 2025-08-28
* @Version: V1.0
*/
@Tag(name="标签")
@RestController
@RequestMapping("/gen/aioltag/aiolTag")
@Slf4j
public class AiolTagController extends JeecgController<AiolTag, IAiolTagService> {
@Autowired
private IAiolTagService aiolTagService;
/**
* 分页列表查询
*
* @param aiolTag
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "标签-分页列表查询")
@Operation(summary="标签-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<AiolTag>> queryPageList(AiolTag aiolTag,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<AiolTag> queryWrapper = QueryGenerator.initQueryWrapper(aiolTag, req.getParameterMap());
Page<AiolTag> page = new Page<AiolTag>(pageNo, pageSize);
IPage<AiolTag> pageList = aiolTagService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param aiolTag
* @return
*/
@AutoLog(value = "标签-添加")
@Operation(summary="标签-添加")
@RequiresPermissions("gen.aioltag:aiol_tag:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody AiolTag aiolTag) {
aiolTagService.save(aiolTag);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param aiolTag
* @return
*/
@AutoLog(value = "标签-编辑")
@Operation(summary="标签-编辑")
@RequiresPermissions("gen.aioltag:aiol_tag:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody AiolTag aiolTag) {
aiolTagService.updateById(aiolTag);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "标签-通过id删除")
@Operation(summary="标签-通过id删除")
@RequiresPermissions("gen.aioltag:aiol_tag:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
aiolTagService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "标签-批量删除")
@Operation(summary="标签-批量删除")
@RequiresPermissions("gen.aioltag:aiol_tag:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.aiolTagService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "标签-通过id查询")
@Operation(summary="标签-通过id查询")
@GetMapping(value = "/queryById")
public Result<AiolTag> queryById(@RequestParam(name="id",required=true) String id) {
AiolTag aiolTag = aiolTagService.getById(id);
if(aiolTag==null) {
return Result.error("未找到对应数据");
}
return Result.OK(aiolTag);
}
/**
* 导出excel
*
* @param request
* @param aiolTag
*/
@RequiresPermissions("gen.aioltag:aiol_tag:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, AiolTag aiolTag) {
return super.exportXls(request, aiolTag, AiolTag.class, "标签");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.aioltag:aiol_tag:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, AiolTag.class);
}
}

View File

@ -1,4 +1,4 @@
package org.jeecg.modules.learn.gen.entity;
package org.jeecg.modules.gen.aioltag.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
@ -20,23 +20,39 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 课程
* @Description: 标签
* @Author: jeecg-boot
* @Date: 2025-08-07
* @Date: 2025-08-28
* @Version: V1.0
*/
@Data
@TableName("course")
@TableName("aiol_tag")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="课程")
public class Course implements Serializable {
@Schema(description="标签")
public class AiolTag implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**标签名*/
@Excel(name = "标签名", width = 15)
@Schema(description = "标签名")
private java.lang.String name;
/**目标类型*/
@Excel(name = "目标类型", width = 15)
@Schema(description = "目标类型")
private java.lang.String targetType;
/**目标id*/
@Excel(name = "目标id", width = 15)
@Schema(description = "目标id")
private java.lang.String targetId;
/**描述*/
@Excel(name = "描述", width = 15)
@Schema(description = "描述")
private java.lang.String description;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
@ -53,24 +69,4 @@ public class Course implements Serializable {
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**课程名*/
@Excel(name = "课程名", width = 15)
@Schema(description = "课程名")
private java.lang.String name;
/**图片*/
@Excel(name = "图片", width = 15)
@Schema(description = "图片")
private java.lang.String cover;
/**描述*/
@Excel(name = "描述", width = 15)
@Schema(description = "描述")
private java.lang.String description;
/**所属分类*/
@Excel(name = "所属分类", width = 15, dictTable = "demo", dicText = "name", dicCode = "id")
@Dict(dictTable = "demo", dicText = "name", dicCode = "id")
@Schema(description = "所属分类")
private java.lang.String categoryId;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.aioltag.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.aioltag.entity.AiolTag;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 标签
* @Author: jeecg-boot
* @Date: 2025-08-28
* @Version: V1.0
*/
public interface AiolTagMapper extends BaseMapper<AiolTag> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.aioltag.mapper.AiolTagMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.aioltag.service;
import org.jeecg.modules.gen.aioltag.entity.AiolTag;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 标签
* @Author: jeecg-boot
* @Date: 2025-08-28
* @Version: V1.0
*/
public interface IAiolTagService extends IService<AiolTag> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.aioltag.service.impl;
import org.jeecg.modules.gen.aioltag.entity.AiolTag;
import org.jeecg.modules.gen.aioltag.mapper.AiolTagMapper;
import org.jeecg.modules.gen.aioltag.service.IAiolTagService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 标签
* @Author: jeecg-boot
* @Date: 2025-08-28
* @Version: V1.0
*/
@Service
public class AiolTagServiceImpl extends ServiceImpl<AiolTagMapper, AiolTag> implements IAiolTagService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.comment.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.comment.entity.Comment;
import org.jeecg.modules.gen.comment.service.ICommentService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 评论
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
@Tag(name="评论")
@RestController
@RequestMapping("/gen/comment/comment")
@Slf4j
public class CommentController extends JeecgController<Comment, ICommentService> {
@Autowired
private ICommentService commentService;
/**
* 分页列表查询
*
* @param comment
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "评论-分页列表查询")
@Operation(summary="评论-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<Comment>> queryPageList(Comment comment,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<Comment> queryWrapper = QueryGenerator.initQueryWrapper(comment, req.getParameterMap());
Page<Comment> page = new Page<Comment>(pageNo, pageSize);
IPage<Comment> pageList = commentService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param comment
* @return
*/
@AutoLog(value = "评论-添加")
@Operation(summary="评论-添加")
@RequiresPermissions("gen.comment:comment:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody Comment comment) {
commentService.save(comment);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param comment
* @return
*/
@AutoLog(value = "评论-编辑")
@Operation(summary="评论-编辑")
@RequiresPermissions("gen.comment:comment:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody Comment comment) {
commentService.updateById(comment);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "评论-通过id删除")
@Operation(summary="评论-通过id删除")
@RequiresPermissions("gen.comment:comment:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
commentService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "评论-批量删除")
@Operation(summary="评论-批量删除")
@RequiresPermissions("gen.comment:comment:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.commentService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "评论-通过id查询")
@Operation(summary="评论-通过id查询")
@GetMapping(value = "/queryById")
public Result<Comment> queryById(@RequestParam(name="id",required=true) String id) {
Comment comment = commentService.getById(id);
if(comment==null) {
return Result.error("未找到对应数据");
}
return Result.OK(comment);
}
/**
* 导出excel
*
* @param request
* @param comment
*/
@RequiresPermissions("gen.comment:comment:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, Comment comment) {
return super.exportXls(request, comment, Comment.class, "评论");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.comment:comment:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, Comment.class);
}
}

View File

@ -0,0 +1,77 @@
package org.jeecg.modules.gen.comment.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 评论
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
@Data
@TableName("comment")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="评论")
public class Comment implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**用户id*/
@Excel(name = "用户id", width = 15)
@Schema(description = "用户id")
private java.lang.String userId;
/**目标类型*/
@Excel(name = "目标类型", width = 15)
@Schema(description = "目标类型")
private java.lang.String targetType;
/**目标id*/
@Excel(name = "目标id", width = 15)
@Schema(description = "目标id")
private java.lang.String targetId;
/**内容*/
@Excel(name = "内容", width = 15)
@Schema(description = "内容")
private java.lang.String content;
/**图片*/
@Excel(name = "图片", width = 15)
@Schema(description = "图片")
private java.lang.String imgs;
/**是否置顶*/
@Excel(name = "是否置顶", width = 15)
@Schema(description = "是否置顶")
private java.lang.Integer izTop;
/**点赞数*/
@Excel(name = "点赞数", width = 15)
@Schema(description = "点赞数")
private java.lang.Integer likeCount;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.comment.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.comment.entity.Comment;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 评论
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
public interface CommentMapper extends BaseMapper<Comment> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.comment.mapper.CommentMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.comment.service;
import org.jeecg.modules.gen.comment.entity.Comment;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 评论
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
public interface ICommentService extends IService<Comment> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.comment.service.impl;
import org.jeecg.modules.gen.comment.entity.Comment;
import org.jeecg.modules.gen.comment.mapper.CommentMapper;
import org.jeecg.modules.gen.comment.service.ICommentService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 评论
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements ICommentService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.contentconfig.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.contentconfig.entity.ContentConfig;
import org.jeecg.modules.gen.contentconfig.service.IContentConfigService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 内容配置
* @Author: jeecg-boot
* @Date: 2025-08-25
* @Version: V1.0
*/
@Tag(name="内容配置")
@RestController
@RequestMapping("/gen/contentconfig/contentConfig")
@Slf4j
public class ContentConfigController extends JeecgController<ContentConfig, IContentConfigService> {
@Autowired
private IContentConfigService contentConfigService;
/**
* 分页列表查询
*
* @param contentConfig
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "内容配置-分页列表查询")
@Operation(summary="内容配置-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<ContentConfig>> queryPageList(ContentConfig contentConfig,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<ContentConfig> queryWrapper = QueryGenerator.initQueryWrapper(contentConfig, req.getParameterMap());
Page<ContentConfig> page = new Page<ContentConfig>(pageNo, pageSize);
IPage<ContentConfig> pageList = contentConfigService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param contentConfig
* @return
*/
@AutoLog(value = "内容配置-添加")
@Operation(summary="内容配置-添加")
@RequiresPermissions("gen.contentconfig:content_config:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody ContentConfig contentConfig) {
contentConfigService.save(contentConfig);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param contentConfig
* @return
*/
@AutoLog(value = "内容配置-编辑")
@Operation(summary="内容配置-编辑")
@RequiresPermissions("gen.contentconfig:content_config:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody ContentConfig contentConfig) {
contentConfigService.updateById(contentConfig);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "内容配置-通过id删除")
@Operation(summary="内容配置-通过id删除")
@RequiresPermissions("gen.contentconfig:content_config:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
contentConfigService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "内容配置-批量删除")
@Operation(summary="内容配置-批量删除")
@RequiresPermissions("gen.contentconfig:content_config:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.contentConfigService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "内容配置-通过id查询")
@Operation(summary="内容配置-通过id查询")
@GetMapping(value = "/queryById")
public Result<ContentConfig> queryById(@RequestParam(name="id",required=true) String id) {
ContentConfig contentConfig = contentConfigService.getById(id);
if(contentConfig==null) {
return Result.error("未找到对应数据");
}
return Result.OK(contentConfig);
}
/**
* 导出excel
*
* @param request
* @param contentConfig
*/
@RequiresPermissions("gen.contentconfig:content_config:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, ContentConfig contentConfig) {
return super.exportXls(request, contentConfig, ContentConfig.class, "内容配置");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.contentconfig:content_config:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, ContentConfig.class);
}
}

View File

@ -0,0 +1,56 @@
package org.jeecg.modules.gen.contentconfig.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 内容配置
* @Author: jeecg-boot
* @Date: 2025-08-25
* @Version: V1.0
*/
@Data
@TableName("content_config")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="内容配置")
public class ContentConfig implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**配置标识*/
@Excel(name = "配置标识", width = 15)
@Schema(description = "配置标识")
private java.lang.String contentKey;
/**配置值*/
@Excel(name = "配置值", width = 15)
@Schema(description = "配置值")
private java.lang.String contentValue;
/**值类型*/
@Excel(name = "值类型", width = 15)
@Schema(description = "值类型")
private java.lang.String valueType;
/**描述*/
@Excel(name = "描述", width = 15)
@Schema(description = "描述")
private java.lang.String description;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.contentconfig.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.contentconfig.entity.ContentConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 内容配置
* @Author: jeecg-boot
* @Date: 2025-08-25
* @Version: V1.0
*/
public interface ContentConfigMapper extends BaseMapper<ContentConfig> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.contentconfig.mapper.ContentConfigMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.contentconfig.service;
import org.jeecg.modules.gen.contentconfig.entity.ContentConfig;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 内容配置
* @Author: jeecg-boot
* @Date: 2025-08-25
* @Version: V1.0
*/
public interface IContentConfigService extends IService<ContentConfig> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.contentconfig.service.impl;
import org.jeecg.modules.gen.contentconfig.entity.ContentConfig;
import org.jeecg.modules.gen.contentconfig.mapper.ContentConfigMapper;
import org.jeecg.modules.gen.contentconfig.service.IContentConfigService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 内容配置
* @Author: jeecg-boot
* @Date: 2025-08-25
* @Version: V1.0
*/
@Service
public class ContentConfigServiceImpl extends ServiceImpl<ContentConfigMapper, ContentConfig> implements IContentConfigService {
}

View File

@ -1,4 +1,4 @@
package org.jeecg.modules.learn.gen.controller;
package org.jeecg.modules.gen.course.controller;
import java.util.Arrays;
import java.util.HashMap;
@ -14,9 +14,8 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.learn.gen.entity.Course;
import org.jeecg.modules.learn.gen.service.ICourseService;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.course.service.ICourseService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -40,19 +39,19 @@ import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 课程
* @Description: 课程
* @Author: jeecg-boot
* @Date: 2025-08-07
* @Date: 2025-08-09
* @Version: V1.0
*/
@Tag(name="课程")
@RestController
@RequestMapping("/gen/course")
@RequestMapping("/gen/course/course")
@Slf4j
public class CourseController extends JeecgController<Course, ICourseService> {
@Autowired
private ICourseService courseService;
/**
* 分页列表查询
*
@ -62,8 +61,8 @@ public class CourseController extends JeecgController<Course, ICourseService> {
* @param req
* @return
*/
//@AutoLog(value = "课程-分页列表查询")
@Operation(summary="课程-分页列表查询")
//@AutoLog(value = "课程-分页列表查询")
@Operation(summary="课程-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<Course>> queryPageList(Course course,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@ -71,11 +70,7 @@ public class CourseController extends JeecgController<Course, ICourseService> {
HttpServletRequest req) {
// 自定义查询规则
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
// 自定义多选的查询规则为LIKE_WITH_OR
customeRuleMap.put("categoryId", QueryRuleEnum.LIKE_WITH_OR);
QueryWrapper<Course> queryWrapper = QueryGenerator.initQueryWrapper(course, req.getParameterMap(),customeRuleMap);
QueryWrapper<Course> queryWrapper = QueryGenerator.initQueryWrapper(course, req.getParameterMap());
Page<Course> page = new Page<Course>(pageNo, pageSize);
IPage<Course> pageList = courseService.page(page, queryWrapper);
return Result.OK(pageList);
@ -89,9 +84,14 @@ public class CourseController extends JeecgController<Course, ICourseService> {
*/
@AutoLog(value = "课程-添加")
@Operation(summary="课程-添加")
@RequiresPermissions("gen:course:add")
@RequiresPermissions("gen.course:course:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody Course course) {
// 判断开始时间是否晚于结束时间
if (course.getStartTime().after(course.getEndTime())) {
return Result.error("开始时间不能晚于结束时间");
}
courseService.save(course);
return Result.OK("添加成功!");
@ -105,9 +105,15 @@ public class CourseController extends JeecgController<Course, ICourseService> {
*/
@AutoLog(value = "课程-编辑")
@Operation(summary="课程-编辑")
@RequiresPermissions("gen:course:edit")
@RequiresPermissions("gen.course:course:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody Course course) {
// 判断开始时间是否晚于结束时间
if (course.getStartTime().after(course.getEndTime())) {
return Result.error("开始时间不能晚于结束时间");
}
courseService.updateById(course);
return Result.OK("编辑成功!");
}
@ -120,7 +126,7 @@ public class CourseController extends JeecgController<Course, ICourseService> {
*/
@AutoLog(value = "课程-通过id删除")
@Operation(summary="课程-通过id删除")
@RequiresPermissions("gen:course:delete")
@RequiresPermissions("gen.course:course:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
courseService.removeById(id);
@ -133,9 +139,9 @@ public class CourseController extends JeecgController<Course, ICourseService> {
* @param ids
* @return
*/
@AutoLog(value = "课程-批量删除")
@Operation(summary="课程-批量删除")
@RequiresPermissions("gen:course:deleteBatch")
@AutoLog(value = "课程-批量删除")
@Operation(summary="课程-批量删除")
@RequiresPermissions("gen.course:course:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.courseService.removeByIds(Arrays.asList(ids.split(",")));
@ -148,8 +154,8 @@ public class CourseController extends JeecgController<Course, ICourseService> {
* @param id
* @return
*/
//@AutoLog(value = "课程-通过id查询")
@Operation(summary="课程-通过id查询")
//@AutoLog(value = "课程-通过id查询")
@Operation(summary="课程-通过id查询")
@GetMapping(value = "/queryById")
public Result<Course> queryById(@RequestParam(name="id",required=true) String id) {
Course course = courseService.getById(id);
@ -165,10 +171,10 @@ public class CourseController extends JeecgController<Course, ICourseService> {
* @param request
* @param course
*/
@RequiresPermissions("gen:course:exportXls")
@RequiresPermissions("gen.course:course:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, Course course) {
return super.exportXls(request, course, Course.class, "课程");
return super.exportXls(request, course, Course.class, "课程");
}
/**
@ -178,7 +184,7 @@ public class CourseController extends JeecgController<Course, ICourseService> {
* @param response
* @return
*/
@RequiresPermissions("gen:course:importExcel")
@RequiresPermissions("gen.course:course:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, Course.class);

View File

@ -0,0 +1,140 @@
package org.jeecg.modules.gen.course.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 课程表
* @Author: jeecg-boot
* @Date: 2025-08-09
* @Version: V1.0
*/
@Data
@TableName("course")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="课程表")
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**课程名*/
@Excel(name = "课程名", width = 15)
@Schema(description = "课程名")
private java.lang.String name;
/**封面图*/
@Excel(name = "封面图", width = 15)
@Schema(description = "封面图")
private java.lang.String cover;
/**介绍视频*/
@Excel(name = "介绍视频", width = 15)
@Schema(description = "介绍视频")
private java.lang.String video;
/**学校*/
@Excel(name = "学校", width = 15)
@Schema(description = "学校")
private java.lang.String school;
/**课程概述*/
@Excel(name = "课程概述", width = 15)
@Schema(description = "课程概述")
private java.lang.String description;
/**课程类型*/
@Excel(name = "课程类型", width = 15, dicCode = "course_type")
@Dict(dicCode = "course_type")
@Schema(description = "课程类型")
private java.lang.Integer type;
/**授课目标*/
@Excel(name = "授课目标", width = 15)
@Schema(description = "授课目标")
private java.lang.String target;
/**课程难度*/
@Excel(name = "课程难度", width = 15, dicCode = "course_difficulty")
@Dict(dicCode = "course_difficulty")
@Schema(description = "课程难度")
private java.lang.Integer difficulty;
/**所属专题*/
@Excel(name = "所属专题", width = 15, dicCode = "course_subject")
@Dict(dicCode = "course_subject")
@Schema(description = "所属专题")
private java.lang.String subject;
/**课程大纲*/
@Excel(name = "课程大纲", width = 15)
@Schema(description = "课程大纲")
private java.lang.String outline;
/**预备知识*/
@Excel(name = "预备知识", width = 15)
@Schema(description = "预备知识")
private java.lang.String prerequisite;
/**参考资料*/
@Excel(name = "参考资料", width = 15)
@Schema(description = "参考资料")
private java.lang.String reference;
/**学时安排*/
@Excel(name = "学时安排", width = 15)
@Schema(description = "学时安排")
private java.lang.String arrangement;
/**开课时间*/
@Excel(name = "开课时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "开课时间")
private java.util.Date startTime;
/**结课时间*/
@Excel(name = "结课时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "结课时间")
private java.util.Date endTime;
/**已报名人数*/
@Excel(name = "已报名人数", width = 15)
@Schema(description = "已报名人数")
private java.lang.Integer enrollCount;
/**最大报名人数*/
@Excel(name = "最大报名人数", width = 15)
@Schema(description = "最大报名人数")
private java.lang.Integer maxEnroll;
/**状态*/
@Excel(name = "状态", width = 15, dicCode = "course_status")
@Dict(dicCode = "course_status")
@Schema(description = "状态")
private java.lang.Integer status;
/**常见问题*/
@Excel(name = "常见问题", width = 15)
@Schema(description = "常见问题")
private java.lang.String question;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建时间*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建时间")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新时间*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新时间")
private java.util.Date updateTime;
}

View File

@ -1,15 +1,15 @@
package org.jeecg.modules.learn.gen.mapper;
package org.jeecg.modules.gen.course.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.learn.gen.entity.Course;
import org.jeecg.modules.gen.course.entity.Course;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 课程
* @Description: 课程
* @Author: jeecg-boot
* @Date: 2025-08-07
* @Date: 2025-08-09
* @Version: V1.0
*/
public interface CourseMapper extends BaseMapper<Course> {

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.course.mapper.CourseMapper">
</mapper>

View File

@ -1,12 +1,12 @@
package org.jeecg.modules.learn.gen.service;
package org.jeecg.modules.gen.course.service;
import org.jeecg.modules.learn.gen.entity.Course;
import org.jeecg.modules.gen.course.entity.Course;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 课程
* @Description: 课程
* @Author: jeecg-boot
* @Date: 2025-08-07
* @Date: 2025-08-09
* @Version: V1.0
*/
public interface ICourseService extends IService<Course> {

View File

@ -1,16 +1,16 @@
package org.jeecg.modules.learn.gen.service.impl;
package org.jeecg.modules.gen.course.service.impl;
import org.jeecg.modules.learn.gen.entity.Course;
import org.jeecg.modules.learn.gen.mapper.CourseMapper;
import org.jeecg.modules.learn.gen.service.ICourseService;
import org.jeecg.modules.gen.course.entity.Course;
import org.jeecg.modules.gen.course.mapper.CourseMapper;
import org.jeecg.modules.gen.course.service.ICourseService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 课程
* @Description: 课程
* @Author: jeecg-boot
* @Date: 2025-08-07
* @Date: 2025-08-09
* @Version: V1.0
*/
@Service

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.coursecategory.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import org.jeecg.modules.gen.coursecategory.service.ICourseCategoryService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 课程分类表
* @Author: jeecg-boot
* @Date: 2025-08-09
* @Version: V1.0
*/
@Tag(name="课程分类表")
@RestController
@RequestMapping("/gen/coursecategory/courseCategory")
@Slf4j
public class CourseCategoryController extends JeecgController<CourseCategory, ICourseCategoryService> {
@Autowired
private ICourseCategoryService courseCategoryService;
/**
* 分页列表查询
*
* @param courseCategory
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "课程分类表-分页列表查询")
@Operation(summary="课程分类表-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<CourseCategory>> queryPageList(CourseCategory courseCategory,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<CourseCategory> queryWrapper = QueryGenerator.initQueryWrapper(courseCategory, req.getParameterMap());
Page<CourseCategory> page = new Page<CourseCategory>(pageNo, pageSize);
IPage<CourseCategory> pageList = courseCategoryService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param courseCategory
* @return
*/
@AutoLog(value = "课程分类表-添加")
@Operation(summary="课程分类表-添加")
@RequiresPermissions("gen.coursecategory:course_category:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody CourseCategory courseCategory) {
courseCategoryService.save(courseCategory);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param courseCategory
* @return
*/
@AutoLog(value = "课程分类表-编辑")
@Operation(summary="课程分类表-编辑")
@RequiresPermissions("gen.coursecategory:course_category:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody CourseCategory courseCategory) {
courseCategoryService.updateById(courseCategory);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "课程分类表-通过id删除")
@Operation(summary="课程分类表-通过id删除")
@RequiresPermissions("gen.coursecategory:course_category:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
courseCategoryService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "课程分类表-批量删除")
@Operation(summary="课程分类表-批量删除")
@RequiresPermissions("gen.coursecategory:course_category:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.courseCategoryService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "课程分类表-通过id查询")
@Operation(summary="课程分类表-通过id查询")
@GetMapping(value = "/queryById")
public Result<CourseCategory> queryById(@RequestParam(name="id",required=true) String id) {
CourseCategory courseCategory = courseCategoryService.getById(id);
if(courseCategory==null) {
return Result.error("未找到对应数据");
}
return Result.OK(courseCategory);
}
/**
* 导出excel
*
* @param request
* @param courseCategory
*/
@RequiresPermissions("gen.coursecategory:course_category:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, CourseCategory courseCategory) {
return super.exportXls(request, courseCategory, CourseCategory.class, "课程分类表");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.coursecategory:course_category:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, CourseCategory.class);
}
}

View File

@ -0,0 +1,64 @@
package org.jeecg.modules.gen.coursecategory.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 课程分类表
* @Author: jeecg-boot
* @Date: 2025-08-09
* @Version: V1.0
*/
@Data
@TableName("course_category")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="课程分类表")
public class CourseCategory implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**分类名*/
@Excel(name = "分类名", width = 15)
@Schema(description = "分类名")
private java.lang.String name;
/**排序*/
@Excel(name = "排序", width = 15)
@Schema(description = "排序")
private java.lang.Integer sortOrder;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建时间*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建时间")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新时间*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新时间")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.coursecategory.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 课程分类表
* @Author: jeecg-boot
* @Date: 2025-08-09
* @Version: V1.0
*/
public interface CourseCategoryMapper extends BaseMapper<CourseCategory> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.coursecategory.mapper.CourseCategoryMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.coursecategory.service;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 课程分类表
* @Author: jeecg-boot
* @Date: 2025-08-09
* @Version: V1.0
*/
public interface ICourseCategoryService extends IService<CourseCategory> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.coursecategory.service.impl;
import org.jeecg.modules.gen.coursecategory.entity.CourseCategory;
import org.jeecg.modules.gen.coursecategory.mapper.CourseCategoryMapper;
import org.jeecg.modules.gen.coursecategory.service.ICourseCategoryService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 课程分类表
* @Author: jeecg-boot
* @Date: 2025-08-09
* @Version: V1.0
*/
@Service
public class CourseCategoryServiceImpl extends ServiceImpl<CourseCategoryMapper, CourseCategory> implements ICourseCategoryService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.coursesection.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import org.jeecg.modules.gen.coursesection.service.ICourseSectionService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 课程章节
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
@Tag(name="课程章节")
@RestController
@RequestMapping("/gen/coursesection/courseSection")
@Slf4j
public class CourseSectionController extends JeecgController<CourseSection, ICourseSectionService> {
@Autowired
private ICourseSectionService courseSectionService;
/**
* 分页列表查询
*
* @param courseSection
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "课程章节-分页列表查询")
@Operation(summary="课程章节-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<CourseSection>> queryPageList(CourseSection courseSection,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<CourseSection> queryWrapper = QueryGenerator.initQueryWrapper(courseSection, req.getParameterMap());
Page<CourseSection> page = new Page<CourseSection>(pageNo, pageSize);
IPage<CourseSection> pageList = courseSectionService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param courseSection
* @return
*/
@AutoLog(value = "课程章节-添加")
@Operation(summary="课程章节-添加")
@RequiresPermissions("gen.coursesection:course_section:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody CourseSection courseSection) {
courseSectionService.save(courseSection);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param courseSection
* @return
*/
@AutoLog(value = "课程章节-编辑")
@Operation(summary="课程章节-编辑")
@RequiresPermissions("gen.coursesection:course_section:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody CourseSection courseSection) {
courseSectionService.updateById(courseSection);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "课程章节-通过id删除")
@Operation(summary="课程章节-通过id删除")
@RequiresPermissions("gen.coursesection:course_section:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
courseSectionService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "课程章节-批量删除")
@Operation(summary="课程章节-批量删除")
@RequiresPermissions("gen.coursesection:course_section:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.courseSectionService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "课程章节-通过id查询")
@Operation(summary="课程章节-通过id查询")
@GetMapping(value = "/queryById")
public Result<CourseSection> queryById(@RequestParam(name="id",required=true) String id) {
CourseSection courseSection = courseSectionService.getById(id);
if(courseSection==null) {
return Result.error("未找到对应数据");
}
return Result.OK(courseSection);
}
/**
* 导出excel
*
* @param request
* @param courseSection
*/
@RequiresPermissions("gen.coursesection:course_section:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, CourseSection courseSection) {
return super.exportXls(request, courseSection, CourseSection.class, "课程章节");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.coursesection:course_section:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, CourseSection.class);
}
}

View File

@ -0,0 +1,82 @@
package org.jeecg.modules.gen.coursesection.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 课程章节
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
@Data
@TableName("course_section")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="课程章节")
public class CourseSection implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**课程id*/
@Excel(name = "课程id", width = 15)
@Schema(description = "课程id")
private java.lang.String courseId;
/**章节名*/
@Excel(name = "章节名", width = 15)
@Schema(description = "章节名")
private java.lang.String name;
/**章节类型*/
@Excel(name = "章节类型", width = 15, dicCode = "course_section_type")
@Dict(dicCode = "course_section_type")
@Schema(description = "章节类型")
private java.lang.Integer type;
/**排序号*/
@Excel(name = "排序号", width = 15)
@Schema(description = "排序号")
private java.lang.Integer sortOrder;
/**父章节id*/
@Excel(name = "父章节id", width = 15)
@Schema(description = "父章节id")
private java.lang.String parentId;
/**章节层级*/
@Excel(name = "章节层级", width = 15, dicCode = "course_section_level")
@Dict(dicCode = "course_section_level")
@Schema(description = "章节层级")
private java.lang.Integer level;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.coursesection.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 课程章节
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
public interface CourseSectionMapper extends BaseMapper<CourseSection> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.coursesection.mapper.CourseSectionMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.coursesection.service;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 课程章节
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
public interface ICourseSectionService extends IService<CourseSection> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.coursesection.service.impl;
import org.jeecg.modules.gen.coursesection.entity.CourseSection;
import org.jeecg.modules.gen.coursesection.mapper.CourseSectionMapper;
import org.jeecg.modules.gen.coursesection.service.ICourseSectionService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 课程章节
* @Author: jeecg-boot
* @Date: 2025-08-16
* @Version: V1.0
*/
@Service
public class CourseSectionServiceImpl extends ServiceImpl<CourseSectionMapper, CourseSection> implements ICourseSectionService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.coursesignup.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.coursesignup.entity.CourseSignup;
import org.jeecg.modules.gen.coursesignup.service.ICourseSignupService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 课程报名
* @Author: jeecg-boot
* @Date: 2025-08-19
* @Version: V1.0
*/
@Tag(name="课程报名")
@RestController
@RequestMapping("/gen/coursesignup/courseSignup")
@Slf4j
public class CourseSignupController extends JeecgController<CourseSignup, ICourseSignupService> {
@Autowired
private ICourseSignupService courseSignupService;
/**
* 分页列表查询
*
* @param courseSignup
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "课程报名-分页列表查询")
@Operation(summary="课程报名-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<CourseSignup>> queryPageList(CourseSignup courseSignup,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<CourseSignup> queryWrapper = QueryGenerator.initQueryWrapper(courseSignup, req.getParameterMap());
Page<CourseSignup> page = new Page<CourseSignup>(pageNo, pageSize);
IPage<CourseSignup> pageList = courseSignupService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param courseSignup
* @return
*/
@AutoLog(value = "课程报名-添加")
@Operation(summary="课程报名-添加")
@RequiresPermissions("gen.coursesignup:course_signup:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody CourseSignup courseSignup) {
courseSignupService.save(courseSignup);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param courseSignup
* @return
*/
@AutoLog(value = "课程报名-编辑")
@Operation(summary="课程报名-编辑")
@RequiresPermissions("gen.coursesignup:course_signup:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody CourseSignup courseSignup) {
courseSignupService.updateById(courseSignup);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "课程报名-通过id删除")
@Operation(summary="课程报名-通过id删除")
@RequiresPermissions("gen.coursesignup:course_signup:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
courseSignupService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "课程报名-批量删除")
@Operation(summary="课程报名-批量删除")
@RequiresPermissions("gen.coursesignup:course_signup:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.courseSignupService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "课程报名-通过id查询")
@Operation(summary="课程报名-通过id查询")
@GetMapping(value = "/queryById")
public Result<CourseSignup> queryById(@RequestParam(name="id",required=true) String id) {
CourseSignup courseSignup = courseSignupService.getById(id);
if(courseSignup==null) {
return Result.error("未找到对应数据");
}
return Result.OK(courseSignup);
}
/**
* 导出excel
*
* @param request
* @param courseSignup
*/
@RequiresPermissions("gen.coursesignup:course_signup:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, CourseSignup courseSignup) {
return super.exportXls(request, courseSignup, CourseSignup.class, "课程报名");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.coursesignup:course_signup:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, CourseSignup.class);
}
}

View File

@ -0,0 +1,64 @@
package org.jeecg.modules.gen.coursesignup.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 课程报名
* @Author: jeecg-boot
* @Date: 2025-08-19
* @Version: V1.0
*/
@Data
@TableName("course_signup")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="课程报名")
public class CourseSignup implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**用户id*/
@Excel(name = "用户id", width = 15)
@Schema(description = "用户id")
private java.lang.String userId;
/**课程id*/
@Excel(name = "课程id", width = 15)
@Schema(description = "课程id")
private java.lang.String courseId;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.coursesignup.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.coursesignup.entity.CourseSignup;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 课程报名
* @Author: jeecg-boot
* @Date: 2025-08-19
* @Version: V1.0
*/
public interface CourseSignupMapper extends BaseMapper<CourseSignup> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.coursesignup.mapper.CourseSignupMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.coursesignup.service;
import org.jeecg.modules.gen.coursesignup.entity.CourseSignup;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 课程报名
* @Author: jeecg-boot
* @Date: 2025-08-19
* @Version: V1.0
*/
public interface ICourseSignupService extends IService<CourseSignup> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.coursesignup.service.impl;
import org.jeecg.modules.gen.coursesignup.entity.CourseSignup;
import org.jeecg.modules.gen.coursesignup.mapper.CourseSignupMapper;
import org.jeecg.modules.gen.coursesignup.service.ICourseSignupService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 课程报名
* @Author: jeecg-boot
* @Date: 2025-08-19
* @Version: V1.0
*/
@Service
public class CourseSignupServiceImpl extends ServiceImpl<CourseSignupMapper, CourseSignup> implements ICourseSignupService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.courseteacher.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.courseteacher.entity.CourseTeacher;
import org.jeecg.modules.gen.courseteacher.service.ICourseTeacherService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 授课教师
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
@Tag(name="授课教师")
@RestController
@RequestMapping("/gen/courseteacher/courseTeacher")
@Slf4j
public class CourseTeacherController extends JeecgController<CourseTeacher, ICourseTeacherService> {
@Autowired
private ICourseTeacherService courseTeacherService;
/**
* 分页列表查询
*
* @param courseTeacher
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "授课教师-分页列表查询")
@Operation(summary="授课教师-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<CourseTeacher>> queryPageList(CourseTeacher courseTeacher,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<CourseTeacher> queryWrapper = QueryGenerator.initQueryWrapper(courseTeacher, req.getParameterMap());
Page<CourseTeacher> page = new Page<CourseTeacher>(pageNo, pageSize);
IPage<CourseTeacher> pageList = courseTeacherService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param courseTeacher
* @return
*/
@AutoLog(value = "授课教师-添加")
@Operation(summary="授课教师-添加")
@RequiresPermissions("gen.courseteacher:course_teacher:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody CourseTeacher courseTeacher) {
courseTeacherService.save(courseTeacher);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param courseTeacher
* @return
*/
@AutoLog(value = "授课教师-编辑")
@Operation(summary="授课教师-编辑")
@RequiresPermissions("gen.courseteacher:course_teacher:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody CourseTeacher courseTeacher) {
courseTeacherService.updateById(courseTeacher);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "授课教师-通过id删除")
@Operation(summary="授课教师-通过id删除")
@RequiresPermissions("gen.courseteacher:course_teacher:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
courseTeacherService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "授课教师-批量删除")
@Operation(summary="授课教师-批量删除")
@RequiresPermissions("gen.courseteacher:course_teacher:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.courseTeacherService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "授课教师-通过id查询")
@Operation(summary="授课教师-通过id查询")
@GetMapping(value = "/queryById")
public Result<CourseTeacher> queryById(@RequestParam(name="id",required=true) String id) {
CourseTeacher courseTeacher = courseTeacherService.getById(id);
if(courseTeacher==null) {
return Result.error("未找到对应数据");
}
return Result.OK(courseTeacher);
}
/**
* 导出excel
*
* @param request
* @param courseTeacher
*/
@RequiresPermissions("gen.courseteacher:course_teacher:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, CourseTeacher courseTeacher) {
return super.exportXls(request, courseTeacher, CourseTeacher.class, "授课教师");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.courseteacher:course_teacher:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, CourseTeacher.class);
}
}

View File

@ -0,0 +1,73 @@
package org.jeecg.modules.gen.courseteacher.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 授课教师
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
@Data
@TableName("course_teacher")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="授课教师")
public class CourseTeacher implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**课程id*/
@Excel(name = "课程id", width = 15)
@Schema(description = "课程id")
private java.lang.String courseId;
/**教师id*/
@Excel(name = "教师id", width = 15)
@Schema(description = "教师id")
private java.lang.String teacherId;
/**授课角色*/
@Excel(name = "授课角色", width = 15, dicCode = "course_role")
@Dict(dicCode = "course_role")
@Schema(description = "授课角色")
private java.lang.String role;
/**显示顺序*/
@Excel(name = "显示顺序", width = 15)
@Schema(description = "显示顺序")
private java.lang.Integer sortOrder;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.courseteacher.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.courseteacher.entity.CourseTeacher;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 授课教师
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
public interface CourseTeacherMapper extends BaseMapper<CourseTeacher> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.courseteacher.mapper.CourseTeacherMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.courseteacher.service;
import org.jeecg.modules.gen.courseteacher.entity.CourseTeacher;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 授课教师
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
public interface ICourseTeacherService extends IService<CourseTeacher> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.courseteacher.service.impl;
import org.jeecg.modules.gen.courseteacher.entity.CourseTeacher;
import org.jeecg.modules.gen.courseteacher.mapper.CourseTeacherMapper;
import org.jeecg.modules.gen.courseteacher.service.ICourseTeacherService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 授课教师
* @Author: jeecg-boot
* @Date: 2025-08-14
* @Version: V1.0
*/
@Service
public class CourseTeacherServiceImpl extends ServiceImpl<CourseTeacherMapper, CourseTeacher> implements ICourseTeacherService {
}

View File

@ -0,0 +1,182 @@
package org.jeecg.modules.gen.entitylink.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.gen.entitylink.entity.EntityLink;
import org.jeecg.modules.gen.entitylink.service.IEntityLinkService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 主体绑定
* @Author: jeecg-boot
* @Date: 2025-08-12
* @Version: V1.0
*/
@Tag(name="主体绑定")
@RestController
@RequestMapping("/gen/entitylink/entityLink")
@Slf4j
public class EntityLinkController extends JeecgController<EntityLink, IEntityLinkService> {
@Autowired
private IEntityLinkService entityLinkService;
/**
* 分页列表查询
*
* @param entityLink
* @param pageNo
* @param pageSize
* @param req
* @return
*/
//@AutoLog(value = "主体绑定-分页列表查询")
@Operation(summary="主体绑定-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<EntityLink>> queryPageList(EntityLink entityLink,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<EntityLink> queryWrapper = QueryGenerator.initQueryWrapper(entityLink, req.getParameterMap());
Page<EntityLink> page = new Page<EntityLink>(pageNo, pageSize);
IPage<EntityLink> pageList = entityLinkService.page(page, queryWrapper);
return Result.OK(pageList);
}
/**
* 添加
*
* @param entityLink
* @return
*/
@AutoLog(value = "主体绑定-添加")
@Operation(summary="主体绑定-添加")
@RequiresPermissions("gen.entitylink:entity_link:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody EntityLink entityLink) {
entityLinkService.save(entityLink);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param entityLink
* @return
*/
@AutoLog(value = "主体绑定-编辑")
@Operation(summary="主体绑定-编辑")
@RequiresPermissions("gen.entitylink:entity_link:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody EntityLink entityLink) {
entityLinkService.updateById(entityLink);
return Result.OK("编辑成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
@AutoLog(value = "主体绑定-通过id删除")
@Operation(summary="主体绑定-通过id删除")
@RequiresPermissions("gen.entitylink:entity_link:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
entityLinkService.removeById(id);
return Result.OK("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
@AutoLog(value = "主体绑定-批量删除")
@Operation(summary="主体绑定-批量删除")
@RequiresPermissions("gen.entitylink:entity_link:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
this.entityLinkService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
/**
* 通过id查询
*
* @param id
* @return
*/
//@AutoLog(value = "主体绑定-通过id查询")
@Operation(summary="主体绑定-通过id查询")
@GetMapping(value = "/queryById")
public Result<EntityLink> queryById(@RequestParam(name="id",required=true) String id) {
EntityLink entityLink = entityLinkService.getById(id);
if(entityLink==null) {
return Result.error("未找到对应数据");
}
return Result.OK(entityLink);
}
/**
* 导出excel
*
* @param request
* @param entityLink
*/
@RequiresPermissions("gen.entitylink:entity_link:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, EntityLink entityLink) {
return super.exportXls(request, entityLink, EntityLink.class, "主体绑定");
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequiresPermissions("gen.entitylink:entity_link:importExcel")
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
return super.importExcel(request, response, EntityLink.class);
}
}

View File

@ -0,0 +1,68 @@
package org.jeecg.modules.gen.entitylink.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import org.jeecg.common.constant.ProvinceCityArea;
import org.jeecg.common.util.SpringContextUtils;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.jeecg.common.aspect.annotation.Dict;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 主体绑定
* @Author: jeecg-boot
* @Date: 2025-08-12
* @Version: V1.0
*/
@Data
@TableName("entity_link")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="主体绑定")
public class EntityLink implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**主体类型*/
@Excel(name = "主体类型", width = 15)
@Schema(description = "主体类型")
private java.lang.String sourceType;
/**主体id*/
@Excel(name = "主体id", width = 15)
@Schema(description = "主体id")
private java.lang.String sourceId;
/**内容类型*/
@Excel(name = "内容类型", width = 15)
@Schema(description = "内容类型")
private java.lang.String targetType;
/**内容id*/
@Excel(name = "内容id", width = 15)
@Schema(description = "内容id")
private java.lang.String targetId;
/**排序*/
@Excel(name = "排序", width = 15)
@Schema(description = "排序")
private java.lang.Integer sortOrder;
/**创建人*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.gen.entitylink.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.gen.entitylink.entity.EntityLink;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 主体绑定
* @Author: jeecg-boot
* @Date: 2025-08-12
* @Version: V1.0
*/
public interface EntityLinkMapper extends BaseMapper<EntityLink> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.gen.entitylink.mapper.EntityLinkMapper">
</mapper>

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.gen.entitylink.service;
import org.jeecg.modules.gen.entitylink.entity.EntityLink;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 主体绑定
* @Author: jeecg-boot
* @Date: 2025-08-12
* @Version: V1.0
*/
public interface IEntityLinkService extends IService<EntityLink> {
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.gen.entitylink.service.impl;
import org.jeecg.modules.gen.entitylink.entity.EntityLink;
import org.jeecg.modules.gen.entitylink.mapper.EntityLinkMapper;
import org.jeecg.modules.gen.entitylink.service.IEntityLinkService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 主体绑定
* @Author: jeecg-boot
* @Date: 2025-08-12
* @Version: V1.0
*/
@Service
public class EntityLinkServiceImpl extends ServiceImpl<EntityLinkMapper, EntityLink> implements IEntityLinkService {
}

Some files were not shown because too many files have changed in this diff Show More