Merge remote-tracking branch 'origin/dev2' into dev2

This commit is contained in:
Lqc 2025-09-17 01:27:26 +08:00
commit a57ab82151
7 changed files with 247 additions and 11 deletions

View File

@ -37,6 +37,8 @@ public final class EntityLinkConst {
public static final String COURSE = "course"; public static final String COURSE = "course";
// 题库 // 题库
public static final String REPO = "repo"; public static final String REPO = "repo";
// 班级
public static final String CLASS = "class";
} }
/** 资源类型 0:视频,1:图片,2:文档 */ /** 资源类型 0:视频,1:图片,2:文档 */

View File

@ -21,11 +21,14 @@ import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.aiol.dto.CourseWithTeacherInfo; import org.jeecg.modules.aiol.dto.CourseWithTeacherInfo;
import org.jeecg.modules.aiol.dto.AiolCourseSaveDTO; import org.jeecg.modules.aiol.dto.AiolCourseSaveDTO;
import org.jeecg.modules.aiol.dto.TeacherInfo; import org.jeecg.modules.aiol.dto.TeacherInfo;
import org.jeecg.modules.aiol.dto.AiolCourseWithLinkDTO;
import org.jeecg.modules.aiol.entity.*; import org.jeecg.modules.aiol.entity.*;
import org.jeecg.modules.aiol.service.IAiolCourseService; import org.jeecg.modules.aiol.service.IAiolCourseService;
import org.jeecg.modules.aiol.service.IAiolClassService; import org.jeecg.modules.aiol.service.IAiolClassService;
import org.jeecg.modules.aiol.service.IAiolEntityPermissionService; import org.jeecg.modules.aiol.service.IAiolEntityPermissionService;
import org.jeecg.modules.aiol.service.IAiolEntityLinkService;
import org.jeecg.modules.aiol.constant.EntityPermissionConst; import org.jeecg.modules.aiol.constant.EntityPermissionConst;
import org.jeecg.modules.aiol.constant.EntityLinkConst;
import org.jeecg.modules.aiol.mapper.AiolCourseSignupMapper; import org.jeecg.modules.aiol.mapper.AiolCourseSignupMapper;
import org.jeecg.modules.aiol.mapper.AiolCourseTeacherMapper; import org.jeecg.modules.aiol.mapper.AiolCourseTeacherMapper;
import org.jeecg.modules.aiol.mapper.AiolEntityLinkMapper; import org.jeecg.modules.aiol.mapper.AiolEntityLinkMapper;
@ -70,6 +73,8 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
public class AiolCourseController extends JeecgController<AiolCourse, IAiolCourseService> { public class AiolCourseController extends JeecgController<AiolCourse, IAiolCourseService> {
@Autowired @Autowired
private IAiolCourseService aiolCourseService; private IAiolCourseService aiolCourseService;
@Autowired
private IAiolEntityLinkService entityLinkService;
/** /**
* 分页列表查询 * 分页列表查询
@ -131,14 +136,7 @@ public class AiolCourseController extends JeecgController<AiolCourse, IAiolCours
String[] categoryIds = categoryId.split(","); String[] categoryIds = categoryId.split(",");
for (String catId : categoryIds) { for (String catId : categoryIds) {
if (catId != null && !catId.trim().isEmpty()) { if (catId != null && !catId.trim().isEmpty()) {
AiolEntityLink link = new AiolEntityLink(); entityLinkService.save(EntityLinkConst.SourceType.COURSE_CATEGORY, catId, EntityLinkConst.TargetType.COURSE, dto.getId());
link.setSourceType("course_category");
link.setSourceId(catId.trim());
link.setTargetType("course");
link.setTargetId(dto.getId());
link.setCreateBy(dto.getCreateBy());
link.setCreateTime(new Date());
entityLinkMapper.insert(link);
} }
} }
} }
@ -155,6 +153,24 @@ public class AiolCourseController extends JeecgController<AiolCourse, IAiolCours
} }
try { try {
// 0. 建立课程-班级关联entity_link避免重复
QueryWrapper<AiolEntityLink> linkExistsWrapper = new QueryWrapper<>();
linkExistsWrapper.eq("source_type", EntityLinkConst.SourceType.COURSE)
.eq("source_id", dto.getId())
.eq("target_type", EntityLinkConst.TargetType.CLASS)
.eq("target_id", clsId.trim());
AiolEntityLink existed = entityLinkMapper.selectOne(linkExistsWrapper);
if (existed == null) {
AiolEntityLink classLink = new AiolEntityLink();
classLink.setSourceType(EntityLinkConst.SourceType.COURSE);
classLink.setSourceId(dto.getId());
classLink.setTargetType(EntityLinkConst.TargetType.CLASS);
classLink.setTargetId(clsId.trim());
classLink.setCreateBy(dto.getCreateBy());
classLink.setCreateTime(new Date());
entityLinkMapper.insert(classLink);
}
// 1. 根据班级ID查询学生列表 // 1. 根据班级ID查询学生列表
QueryWrapper<AiolClassStudent> studentWrapper = new QueryWrapper<>(); QueryWrapper<AiolClassStudent> studentWrapper = new QueryWrapper<>();
studentWrapper.eq("class_id", clsId.trim()); studentWrapper.eq("class_id", clsId.trim());
@ -212,7 +228,7 @@ public class AiolCourseController extends JeecgController<AiolCourse, IAiolCours
} }
} }
return Result.OK("添加成功!"); return Result.OK(dto.getId());
} }
/** /**
@ -335,6 +351,8 @@ public class AiolCourseController extends JeecgController<AiolCourse, IAiolCours
@Autowired @Autowired
private IAiolEntityPermissionService aiolEntityPermissionService; private IAiolEntityPermissionService aiolEntityPermissionService;
@Autowired @Autowired
private IAiolEntityLinkService aiolEntityLinkService;
@Autowired
private AiolCourseSignupMapper courseSignupMapper; private AiolCourseSignupMapper courseSignupMapper;
@Autowired @Autowired
private SysUserMapper sysUserMapper; private SysUserMapper sysUserMapper;
@ -601,7 +619,7 @@ public class AiolCourseController extends JeecgController<AiolCourse, IAiolCours
@GetMapping("/teacher_list") @GetMapping("/teacher_list")
@Operation(summary = "查询当前教师创建的课程") @Operation(summary = "查询当前教师创建的课程")
public Result<List<AiolCourse>> queryTeacherCourseList( public Result<List<AiolCourseWithLinkDTO>> queryTeacherCourseList(
@RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "status", required = false) Integer status, @RequestParam(value = "status", required = false) Integer status,
HttpServletRequest request, HttpServletResponse response) { HttpServletRequest request, HttpServletResponse response) {
@ -670,7 +688,34 @@ public class AiolCourseController extends JeecgController<AiolCourse, IAiolCours
resultList.sort(Comparator.comparing(AiolCourse::getCreateTime, resultList.sort(Comparator.comparing(AiolCourse::getCreateTime,
Comparator.nullsLast(java.util.Date::compareTo)).reversed()); Comparator.nullsLast(java.util.Date::compareTo)).reversed());
return Result.OK(resultList); // 5. 组装分类ID与班级ID
List<AiolCourseWithLinkDTO> dtoList = new ArrayList<>();
for (AiolCourse course : resultList) {
AiolCourseWithLinkDTO dto = new AiolCourseWithLinkDTO();
org.springframework.beans.BeanUtils.copyProperties(course, dto);
// 课程的分类关联course_category -> course使用服务反查分类ID列表
List<String> categoryIdList = aiolEntityLinkService.listSourceIds(
EntityLinkConst.TargetType.COURSE,
course.getId(),
EntityLinkConst.SourceType.COURSE_CATEGORY);
if (!categoryIdList.isEmpty()) {
dto.setCategoryId(String.join(",", categoryIdList));
}
// 查询课程的班级关联source_type=course, source_id=courseId, target_type=class使用服务方法
List<String> classIdList = aiolEntityLinkService.listTargetIds(
EntityLinkConst.SourceType.COURSE,
course.getId(),
EntityLinkConst.TargetType.CLASS);
if (!classIdList.isEmpty()) {
dto.setClassId(String.join(",", classIdList));
}
dtoList.add(dto);
}
return Result.OK(dtoList);
} catch (Exception e) { } catch (Exception e) {
log.error("查询教师课程列表失败: error={}", e.getMessage(), e); log.error("查询教师课程列表失败: error={}", e.getMessage(), e);

View File

@ -16,6 +16,7 @@ import org.jeecg.common.util.RedisUtil;
import org.jeecg.config.shiro.IgnoreAuth; import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.aiol.dto.TeacherInfo; import org.jeecg.modules.aiol.dto.TeacherInfo;
import org.jeecg.modules.aiol.dto.UserInfoResponse; import org.jeecg.modules.aiol.dto.UserInfoResponse;
import org.jeecg.modules.aiol.dto.EditProfileDTO;
import org.jeecg.modules.aiol.entity.AiolClass; import org.jeecg.modules.aiol.entity.AiolClass;
import org.jeecg.modules.aiol.entity.AiolClassStudent; import org.jeecg.modules.aiol.entity.AiolClassStudent;
import org.jeecg.modules.aiol.entity.AiolUserInfo; import org.jeecg.modules.aiol.entity.AiolUserInfo;
@ -342,4 +343,106 @@ public class AiolUserController {
return result.error500("注册失败: " + e.getMessage()); return result.error500("注册失败: " + e.getMessage());
} }
} }
@PostMapping("/edit_profile")
@Operation(summary = "编辑个人信息", description = "更新用户的基本信息和扩展信息分别存储到sys_user和aiol_user_info表")
@Transactional(rollbackFor = Exception.class)
public Result<String> editProfile(@RequestBody EditProfileDTO profileDTO, HttpServletRequest request) {
try {
// 1. 从JWT中获取当前用户信息
String username = JwtUtil.getUserNameByToken(request);
if (username == null || username.trim().isEmpty()) {
return Result.error(401, "用户未登录或token无效");
}
SysUser currentUser = sysUserService.getUserByName(username);
if (currentUser == null) {
return Result.error(404, "用户不存在");
}
String id = currentUser.getId();
// 2. 更新sys_user表的基本信息
SysUser userToUpdate = new SysUser();
userToUpdate.setId(id);
if (profileDTO.getRealname() != null) {
userToUpdate.setRealname(profileDTO.getRealname());
}
if (profileDTO.getAvatar() != null) {
userToUpdate.setAvatar(profileDTO.getAvatar());
}
if (profileDTO.getBirthday() != null) {
userToUpdate.setBirthday(profileDTO.getBirthday());
}
if (profileDTO.getSex() != null) {
userToUpdate.setSex(profileDTO.getSex());
}
if (profileDTO.getEmail() != null) {
userToUpdate.setEmail(profileDTO.getEmail());
}
if (profileDTO.getPhone() != null) {
userToUpdate.setPhone(profileDTO.getPhone());
}
// 设置更新信息
userToUpdate.setUpdateBy(username);
userToUpdate.setUpdateTime(new Date());
boolean userUpdated = sysUserService.updateById(userToUpdate);
if (!userUpdated) {
return Result.error(500, "更新用户基本信息失败");
}
// 3. 更新aiol_user_info表的扩展信息
AiolUserInfo userInfo = userInfoMapper.selectOne(
new QueryWrapper<AiolUserInfo>().eq("user_id", id));
if (userInfo == null) {
// 如果扩展信息不存在创建新记录
userInfo = new AiolUserInfo();
userInfo.setUserId(id);
userInfo.setCreateBy(username);
userInfo.setCreateTime(new Date());
}
// 更新扩展信息字段
if (profileDTO.getMajor() != null) {
userInfo.setMajor(profileDTO.getMajor());
}
if (profileDTO.getCollege() != null) {
userInfo.setCollege(profileDTO.getCollege());
}
if (profileDTO.getEducation() != null) {
userInfo.setEducation(profileDTO.getEducation());
}
if (profileDTO.getTitle() != null) {
userInfo.setTitle(profileDTO.getTitle());
}
// 设置更新信息
userInfo.setUpdateBy(username);
userInfo.setUpdateTime(new Date());
boolean userInfoUpdated;
if (userInfo.getId() == null) {
// 新增记录
userInfoUpdated = userInfoMapper.insert(userInfo) > 0;
} else {
// 更新记录
userInfoUpdated = userInfoMapper.updateById(userInfo) > 0;
}
if (!userInfoUpdated) {
return Result.error(500, "更新用户扩展信息失败");
}
log.info("用户个人信息更新成功: userId={}, username={}", id, username);
return Result.OK("个人信息更新成功");
} catch (Exception e) {
log.error("编辑个人信息失败: {}", e.getMessage(), e);
return Result.error(500, "编辑个人信息失败: " + e.getMessage());
}
}
} }

View File

@ -0,0 +1,18 @@
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.AiolCourse;
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(description = "课程DTO包含分类ID和班级ID逗号分隔")
public class AiolCourseWithLinkDTO extends AiolCourse {
@Schema(description = "课程分类ID多个以逗号分隔")
private String categoryId;
@Schema(description = "班级ID多个以逗号分隔")
private String classId;
}

View File

@ -0,0 +1,46 @@
package org.jeecg.modules.aiol.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 编辑个人信息DTO
*/
@Data
@Schema(description = "编辑个人信息DTO")
public class EditProfileDTO {
@Schema(description = "真实姓名")
private String realname;
@Schema(description = "头像")
private String avatar;
@Schema(description = "生日")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "GMT+8")
private Date birthday;
@Schema(description = "性别1男 2")
private Integer sex;
@Schema(description = "邮箱")
private String email;
@Schema(description = "电话")
private String phone;
@Schema(description = "专业")
private String major;
@Schema(description = "学院")
private String college;
@Schema(description = "学历")
private String education;
@Schema(description = "职称")
private String title;
}

View File

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

View File

@ -32,6 +32,19 @@ public class AiolEntityLinkServiceImpl extends ServiceImpl<AiolEntityLinkMapper,
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public List<String> listSourceIds(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);
return this.list(qw).stream()
.map(AiolEntityLink::getSourceId)
.distinct()
.collect(Collectors.toList());
}
@Override @Override
public void save(String sourceType, String sourceId, String targetType, String targetId) { public void save(String sourceType, String sourceId, String targetType, String targetId) {
AiolEntityLink entityLink = new AiolEntityLink(); AiolEntityLink entityLink = new AiolEntityLink();