feat: 🎸 接口补充

This commit is contained in:
GoCo 2025-09-21 16:25:15 +08:00
parent 40aa49a5ba
commit 5529646506
11 changed files with 324 additions and 32 deletions

View File

@ -365,4 +365,33 @@ public class AiolCommentController extends JeecgController<AiolComment, IAiolCom
return Result.error("点赞失败: " + e.getMessage());
}
}
@AutoLog(value = "评论-置顶")
@Operation(summary = "置顶评论", description = "将指定评论置顶设置iz_top字段为1")
@RequiresPermissions("aiol:aiol_comment:edit")
@GetMapping(value = "/top/{commentId}")
public Result<String> topComment(@PathVariable("commentId") String commentId) {
try {
// 1. 查询评论是否存在
AiolComment comment = aiolCommentService.getById(commentId);
if (comment == null) {
return Result.error("评论不存在");
}
// 2. 设置置顶状态
comment.setIzTop(1);
boolean updated = aiolCommentService.updateById(comment);
if (!updated) {
return Result.error("置顶失败");
}
log.info("评论置顶成功: commentId={}", commentId);
return Result.OK("置顶成功!");
} catch (Exception e) {
log.error("评论置顶失败: commentId={}, error={}", commentId, e.getMessage(), e);
return Result.error("置顶失败: " + e.getMessage());
}
}
}

View File

@ -16,8 +16,12 @@ import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.aiol.entity.AiolDiscussion;
import org.jeecg.modules.aiol.dto.DiscussionWithSectionDTO;
import org.jeecg.modules.aiol.dto.AiolDiscussionSaveDTO;
import org.jeecg.modules.aiol.service.IAiolDiscussionService;
import org.jeecg.modules.aiol.service.IAiolEntityLinkService;
import org.jeecg.modules.aiol.service.IAiolCourseSectionService;
import org.jeecg.modules.aiol.entity.AiolCourseSection;
import org.jeecg.modules.aiol.constant.EntityLinkConst;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
@ -61,6 +65,8 @@ public class AiolDiscussionController extends JeecgController<AiolDiscussion, IA
@Autowired
private IAiolEntityLinkService aiolEntityLinkService;
@Autowired
private IAiolCourseSectionService aiolCourseSectionService;
@Autowired
private ISysBaseAPI sysBaseApi;
/**
@ -90,21 +96,26 @@ public class AiolDiscussionController extends JeecgController<AiolDiscussion, IA
/**
* 添加
*
* @param aiolDiscussion
* @param sectionId 可选的章节ID如果传入则创建与章节的关联关系
* @param aiolDiscussionSaveDTO 讨论保存DTO包含章节ID
* @return
*/
@AutoLog(value = "讨论-添加")
@Operation(summary="讨论-添加", description="添加讨论,可选择关联到指定章节")
@RequiresPermissions("aiol:aiol_discussion:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody AiolDiscussion aiolDiscussion,
@RequestParam(value = "sectionId", required = false) String sectionId) {
public Result<String> add(@RequestBody AiolDiscussionSaveDTO aiolDiscussionSaveDTO) {
try {
// 创建讨论实体
AiolDiscussion aiolDiscussion = new AiolDiscussion();
aiolDiscussion.setTitle(aiolDiscussionSaveDTO.getTitle());
aiolDiscussion.setDescription(aiolDiscussionSaveDTO.getDescription());
aiolDiscussion.setCourseId(aiolDiscussionSaveDTO.getCourseId());
// 保存讨论记录
aiolDiscussionService.save(aiolDiscussion);
// 如果传入了sectionId创建与章节的关联关系
String sectionId = aiolDiscussionSaveDTO.getSectionId();
if (sectionId != null && !sectionId.trim().isEmpty()) {
aiolEntityLinkService.save(
EntityLinkConst.SourceType.COURSE_SECTION,
@ -115,7 +126,7 @@ public class AiolDiscussionController extends JeecgController<AiolDiscussion, IA
log.info("讨论 {} 成功关联到章节 {}", aiolDiscussion.getId(), sectionId);
}
return Result.OK("添加成功!");
return Result.OK(aiolDiscussion.getId());
} catch (Exception e) {
log.error("添加讨论失败: {}", e.getMessage(), e);
return Result.error("添加讨论失败: " + e.getMessage());
@ -211,22 +222,71 @@ public class AiolDiscussionController extends JeecgController<AiolDiscussion, IA
}
@AutoLog(value = "讨论-查询课程下的讨论列表")
@Operation(summary = "查询课程讨论列表", description = "查询课程讨论列表")
@Operation(summary = "查询课程讨论列表", description = "查询课程讨论列表包含关联的章节ID")
@GetMapping(value = "/teacher_list")
public Result<List<AiolDiscussion>> queryCourseDiscussions(HttpServletRequest request, @RequestParam(value = "courseId") String courseId) {
public Result<List<DiscussionWithSectionDTO>> queryCourseDiscussions(HttpServletRequest request, @RequestParam(value = "courseId") String courseId) {
try {
// 2. 查询课程下的讨论列表
// 1. 查询课程下的讨论列表
QueryWrapper<AiolDiscussion> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("course_id", courseId)
.orderByDesc("create_time");
List<AiolDiscussion> discussionList = aiolDiscussionService.list(queryWrapper);
return Result.OK(discussionList);
// 2. 转换为包含章节信息的DTO列表
List<DiscussionWithSectionDTO> resultList = discussionList.stream()
.map(this::convertToDiscussionWithSection)
.collect(Collectors.toList());
return Result.OK(resultList);
} catch (Exception e) {
log.error("查询用户讨论列表失败: error={}", e.getMessage(), e);
return Result.error("查询用户讨论列表失败: " + e.getMessage());
log.error("查询课程讨论列表失败: error={}", e.getMessage(), e);
return Result.error("查询课程讨论列表失败: " + e.getMessage());
}
}
/**
* 将AiolDiscussion转换为包含章节信息的DTO
* @param discussion 讨论实体
* @return 包含章节ID的DTO
*/
private DiscussionWithSectionDTO convertToDiscussionWithSection(AiolDiscussion discussion) {
DiscussionWithSectionDTO dto = new DiscussionWithSectionDTO();
// 复制基本属性
dto.setId(discussion.getId());
dto.setTitle(discussion.getTitle());
dto.setDescription(discussion.getDescription());
dto.setCourseId(discussion.getCourseId());
dto.setCreateBy(discussion.getCreateBy());
dto.setCreateTime(discussion.getCreateTime());
dto.setUpdateBy(discussion.getUpdateBy());
dto.setUpdateTime(discussion.getUpdateTime());
try {
// 查询关联的章节ID
String sectionId = aiolEntityLinkService.listSourceId(
EntityLinkConst.TargetType.DISCUSSION,
discussion.getId(),
EntityLinkConst.SourceType.COURSE_SECTION
);
if (sectionId != null) {
dto.setSectionId(sectionId);
// 查询章节名称
AiolCourseSection section = aiolCourseSectionService.getById(sectionId);
if (section != null && section.getName() != null) {
dto.setSectionName(section.getName());
}
}
} catch (Exception e) {
log.error("查询讨论关联章节失败: discussionId={}, error={}", discussion.getId(), e.getMessage(), e);
// 即使查询失败也返回基本的讨论信息
}
return dto;
}
}

View File

@ -22,10 +22,15 @@ import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.aiol.dto.AiolHomeworkSaveDTO;
import org.jeecg.modules.aiol.dto.StudentSubmitHomework;
import org.jeecg.modules.aiol.dto.HomeworkWithDetailsDTO;
import org.jeecg.modules.aiol.entity.AiolHomework;
import org.jeecg.modules.aiol.entity.AiolHomeworkSubmit;
import org.jeecg.modules.aiol.entity.AiolClass;
import org.jeecg.modules.aiol.entity.AiolCourseSection;
import org.jeecg.modules.aiol.service.IAiolHomeworkService;
import org.jeecg.modules.aiol.service.IAiolEntityLinkService;
import org.jeecg.modules.aiol.service.IAiolClassService;
import org.jeecg.modules.aiol.service.IAiolCourseSectionService;
import org.jeecg.modules.aiol.constant.EntityLinkConst;
import org.jeecg.modules.aiol.mapper.AiolClassStudentMapper;
import org.jeecg.modules.aiol.mapper.AiolCourseSignupMapper;
@ -162,14 +167,17 @@ public class AiolHomeworkController extends JeecgController<AiolHomework, IAiolH
* @return
*/
//@AutoLog(value = "作业-通过id查询")
@Operation(summary = "作业-通过id查询")
@Operation(summary = "作业-通过id查询", description = "根据ID查询作业详情包含班级名和章节信息")
@GetMapping(value = "/queryById")
public Result<AiolHomework> queryById(@RequestParam(name = "id", required = true) String id) {
public Result<HomeworkWithDetailsDTO> queryById(@RequestParam(name = "id", required = true) String id) {
AiolHomework aiolHomework = aiolHomeworkService.getById(id);
if (aiolHomework == null) {
return Result.error("未找到对应数据");
}
return Result.OK(aiolHomework);
// 转换为包含详情的DTO
HomeworkWithDetailsDTO result = convertToHomeworkWithDetails(aiolHomework);
return Result.OK(result);
}
/**
@ -212,6 +220,12 @@ public class AiolHomeworkController extends JeecgController<AiolHomework, IAiolH
@Autowired
private ISysBaseAPI sysBaseApi;
@Autowired
private IAiolClassService aiolClassService;
@Autowired
private IAiolCourseSectionService aiolCourseSectionService;
@GetMapping("/course/{courseId}")
@Operation(summary = "查询课程作业")
public Result<List<AiolHomework>> list(@PathVariable String courseId) {
@ -219,9 +233,9 @@ public class AiolHomeworkController extends JeecgController<AiolHomework, IAiolH
}
@AutoLog(value = "作业-教师端查询作业列表")
@Operation(summary = "查询课程作业列表", description = "查询当前登录教师创建的作业列表")
@Operation(summary = "查询课程作业列表", description = "查询当前登录教师创建的作业列表,包含班级名和章节信息")
@GetMapping(value = "/teacher_list")
public Result<List<AiolHomework>> teacherList(@RequestParam(value = "courseId") String courseId, HttpServletRequest request) {
public Result<List<HomeworkWithDetailsDTO>> teacherList(@RequestParam(value = "courseId") String courseId, HttpServletRequest request) {
try {
QueryWrapper<AiolHomework> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("course_id", courseId)
@ -229,7 +243,12 @@ public class AiolHomeworkController extends JeecgController<AiolHomework, IAiolH
List<AiolHomework> homeworkList = aiolHomeworkService.list(queryWrapper);
return Result.OK(homeworkList);
// 转换为包含详情的DTO列表
List<HomeworkWithDetailsDTO> resultList = homeworkList.stream()
.map(this::convertToHomeworkWithDetails)
.collect(Collectors.toList());
return Result.OK(resultList);
} catch (Exception e) {
log.error("查询教师作业列表失败: error={}", e.getMessage(), e);
@ -422,4 +441,56 @@ public class AiolHomeworkController extends JeecgController<AiolHomework, IAiolH
return Result.error("批阅失败: " + e.getMessage());
}
}
/**
* 将AiolHomework转换为包含详情的DTO
* @param homework 作业实体
* @return 包含班级名和章节信息的DTO
*/
private HomeworkWithDetailsDTO convertToHomeworkWithDetails(AiolHomework homework) {
HomeworkWithDetailsDTO dto = new HomeworkWithDetailsDTO();
BeanUtils.copyProperties(homework, dto);
try {
// 1. 查询班级信息
List<String> classNames = new ArrayList<>();
String classId = homework.getClassId();
if (classId != null && !classId.trim().isEmpty()) {
String[] classIds = classId.split(",");
for (String singleClassId : classIds) {
if (singleClassId != null && !singleClassId.trim().isEmpty()) {
singleClassId = singleClassId.trim();
AiolClass aiolClass = aiolClassService.getById(singleClassId);
if (aiolClass != null && aiolClass.getName() != null) {
classNames.add(aiolClass.getName());
}
}
}
}
dto.setClassNames(classNames);
// 2. 查询章节信息
List<String> sectionIds = entityLinkBizService.listSourceIds(
EntityLinkConst.TargetType.HOMEWORK,
homework.getId(),
EntityLinkConst.SourceType.COURSE_SECTION
);
if (!sectionIds.isEmpty()) {
String sectionId = sectionIds.get(0); // 取第一个章节ID
dto.setSectionId(sectionId);
AiolCourseSection section = aiolCourseSectionService.getById(sectionId);
if (section != null && section.getName() != null) {
dto.setSectionTitle(section.getName());
}
}
} catch (Exception e) {
log.error("转换作业详情失败: homeworkId={}, error={}", homework.getId(), e.getMessage(), e);
// 即使转换失败也返回基本的作业信息
}
return dto;
}
}

View File

@ -0,0 +1,21 @@
package org.jeecg.modules.aiol.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.jeecg.modules.aiol.entity.AiolDiscussion;
/**
* @Description: 讨论保存DTO
* @Author: jeecg-boot
* @Date: 2025-01-16
* @Version: V1.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "讨论保存DTO")
public class AiolDiscussionSaveDTO extends AiolDiscussion {
@Schema(description = "关联的章节ID")
private String sectionId;
}

View File

@ -11,10 +11,6 @@ import org.jeecg.modules.aiol.entity.AiolHomework;
@Data
@Schema(description = "作业保存DTO")
public class AiolHomeworkSaveDTO extends AiolHomework {
@Schema(description = "班级ID多个用逗号分割")
private String classId;
@Schema(description = "章节ID")
private String sectionId;
}

View File

@ -0,0 +1,24 @@
package org.jeecg.modules.aiol.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.jeecg.modules.aiol.entity.AiolDiscussion;
/**
* @Description: 讨论详情DTO
* @Author: jeecg-boot
* @Date: 2025-01-16
* @Version: V1.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "讨论详情")
public class DiscussionWithSectionDTO extends AiolDiscussion {
@Schema(description = "关联的章节ID")
private String sectionId;
@Schema(description = "章节名称")
private String sectionName;
}

View File

@ -0,0 +1,29 @@
package org.jeecg.modules.aiol.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.jeecg.modules.aiol.entity.AiolHomework;
import java.util.List;
/**
* @Description: 作业详情DTO
* @Author: jeecg-boot
* @Date: 2025-01-16
* @Version: V1.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "作业详情")
public class HomeworkWithDetailsDTO extends AiolHomework {
@Schema(description = "班级名称列表")
private List<String> classNames;
@Schema(description = "章节ID")
private String sectionId;
@Schema(description = "章节标题")
private String sectionTitle;
}

View File

@ -41,6 +41,10 @@ public class AiolHomework implements Serializable {
@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 classId;
/**标题*/
@Excel(name = "标题", width = 15)
@Schema(description = "标题")

View File

@ -21,6 +21,15 @@ public interface IAiolEntityLinkService extends IService<AiolEntityLink> {
*/
List<String> listTargetIds(String sourceType, String sourceId, String targetType);
/**
* 根据主体与内容类型查询绑定的 target_id
* @param sourceType 主体类型
* @param sourceId 主体ID
* @param targetType 内容类型
* @return target_id
*/
String listTargetId(String sourceType, String sourceId, String targetType);
/**
* 根据内容与主体类型查询绑定的 source_id 列表
* @param targetType 内容类型
@ -30,6 +39,16 @@ public interface IAiolEntityLinkService extends IService<AiolEntityLink> {
*/
List<String> listSourceIds(String targetType, String targetId, String sourceType);
/**
* 根据内容与主体类型查询绑定的 source_id
* @param targetType 内容类型
* @param targetId 内容ID
* @param sourceType 主体类型
* @return source_id
*/
String listSourceId(String targetType, String targetId, String sourceType);
/**
* 保存主体与内容类型的绑定关系
* @param sourceType 主体类型

View File

@ -54,4 +54,32 @@ public class AiolEntityLinkServiceImpl extends ServiceImpl<AiolEntityLinkMapper,
entityLink.setTargetId(targetId);
this.save(entityLink);
}
@Override
public String listSourceId(String targetType, String targetId, String sourceType) {
LambdaQueryWrapper<AiolEntityLink> qw = new LambdaQueryWrapper<>();
qw.eq(AiolEntityLink::getTargetType, targetType)
.eq(AiolEntityLink::getTargetId, targetId)
.eq(AiolEntityLink::getSourceType, sourceType)
.select(AiolEntityLink::getSourceId)
.last("LIMIT 1");
return this.list(qw).stream()
.map(AiolEntityLink::getSourceId)
.findFirst()
.orElse(null);
}
@Override
public String listTargetId(String sourceType, String sourceId, String targetType) {
LambdaQueryWrapper<AiolEntityLink> qw = new LambdaQueryWrapper<>();
qw.eq(AiolEntityLink::getSourceType, sourceType)
.eq(AiolEntityLink::getSourceId, sourceId)
.eq(AiolEntityLink::getTargetType, targetType)
.select(AiolEntityLink::getTargetId)
.last("LIMIT 1");
return this.list(qw).stream()
.map(AiolEntityLink::getTargetId)
.findFirst()
.orElse(null);
}
}

View File

@ -10,6 +10,11 @@ export const columns: BasicColumn[] = [
align:"center",
dataIndex: 'courseId'
},
{
title: '班级id',
align:"center",
dataIndex: 'classId'
},
{
title: '标题',
align:"center",
@ -76,6 +81,11 @@ export const formSchema: FormSchema[] = [
field: 'courseId',
component: 'Input',
},
{
label: '班级id',
field: 'classId',
component: 'Input',
},
{
label: '标题',
field: 'title',
@ -161,17 +171,18 @@ export const formSchema: FormSchema[] = [
//
export const superQuerySchema = {
courseId: {title: '所属课程id',order: 0,view: 'text', type: 'string',},
title: {title: '标题',order: 1,view: 'text', type: 'string',},
description: {title: '说明',order: 2,view: 'umeditor', type: 'string',},
attachment: {title: '附件',order: 3,view: 'file', type: 'string',},
maxScore: {title: '满分',order: 4,view: 'number', type: 'number',},
passScore: {title: '及格分数',order: 5,view: 'number', type: 'number',},
startTime: {title: '开始时间',order: 6,view: 'datetime', type: 'string',},
endTime: {title: '结束时间',order: 7,view: 'datetime', type: 'string',},
status: {title: '状态',order: 8,view: 'number', type: 'number',dictCode: 'course_status',},
allowMakeup: {title: '是否允许补交',order: 9,view: 'number', type: 'number',},
makeupTime: {title: '补交截止时间',order: 10,view: 'datetime', type: 'string',},
notifyTime: {title: '作业通知时间',order: 11,view: 'number', type: 'number',},
classId: {title: '班级id',order: 1,view: 'text', type: 'string',},
title: {title: '标题',order: 2,view: 'text', type: 'string',},
description: {title: '说明',order: 3,view: 'umeditor', type: 'string',},
attachment: {title: '附件',order: 4,view: 'file', type: 'string',},
maxScore: {title: '满分',order: 5,view: 'number', type: 'number',},
passScore: {title: '及格分数',order: 6,view: 'number', type: 'number',},
startTime: {title: '开始时间',order: 7,view: 'datetime', type: 'string',},
endTime: {title: '结束时间',order: 8,view: 'datetime', type: 'string',},
status: {title: '状态',order: 9,view: 'number', type: 'number',dictCode: 'course_status',},
allowMakeup: {title: '是否允许补交',order: 10,view: 'number', type: 'number',},
makeupTime: {title: '补交截止时间',order: 11,view: 'datetime', type: 'string',},
notifyTime: {title: '作业通知时间',order: 12,view: 'number', type: 'number',},
};
/**