视图修改、接口修改

This commit is contained in:
2025-10-28 19:04:35 +08:00
parent 98c73632bd
commit c5c134fbb3
96 changed files with 7122 additions and 4194 deletions

View File

@@ -37,7 +37,8 @@ CREATE TABLE `tb_resource` (
-- Banner管理表
DROP TABLE IF EXISTS `tb_banner`;
CREATE TABLE `tb_banner` (
`id` VARCHAR(50) NOT NULL COMMENT 'Banner ID',
`id` VARCHAR(50) NOT NULL COMMENT 'ID',
`banner_id` VARCHAR(50) NOT NULL COMMENT 'Banner ID',
`title` VARCHAR(255) NOT NULL COMMENT 'Banner标题',
`image_url` VARCHAR(500) NOT NULL COMMENT 'Banner图片URL',
`link_type` INT(4) DEFAULT 1 COMMENT '链接类型1资源 2课程 3外部链接',
@@ -52,6 +53,7 @@ CREATE TABLE `tb_banner` (
`delete_time` TIMESTAMP NULL DEFAULT NULL COMMENT '删除时间',
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_banner_id` (`banner_id`),
KEY `idx_order` (`order_num`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Banner表';

View File

@@ -1,6 +1,7 @@
package org.xyzh.api.news.banner;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.dto.resource.TbBanner;
import java.util.List;
@@ -21,7 +22,7 @@ public interface BannerService {
* @author yslg
* @since 2025-10-15
*/
ResultDomain<TbBanner> getBannerList(Integer status);
ResultDomain<TbBanner> getBannerList(TbBanner filter);
/**
* @description 根据ID获取Banner详情
@@ -30,7 +31,7 @@ public interface BannerService {
* @author yslg
* @since 2025-10-15
*/
ResultDomain<TbBanner> getBannerById(String bannerID);
ResultDomain<TbBanner> getBannerPage(PageParam pageParam,TbBanner filter);
/**
* @description 创建Banner
@@ -96,4 +97,12 @@ public interface BannerService {
* @since 2025-10-15
*/
ResultDomain<Boolean> batchUpdateBannerOrder(java.util.Map<String, Integer> bannerOrders);
/**
* @description 获取首页横幅列表
* @return ResultDomain<TbBanner> 首页横幅列表
* @author yslg
* @since 2025-10-15
*/
ResultDomain<TbBanner> selectHomeBanners();
}

View File

@@ -1,15 +1,11 @@
package org.xyzh.api.study.course;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.dto.study.TbCourseChapter;
import org.xyzh.common.dto.study.TbCourseNode;
import org.xyzh.common.dto.study.TbLearningRecord;
import org.xyzh.common.vo.CourseVO;
import java.util.List;
import org.xyzh.common.vo.CourseItemVO;
/**
* @description 课程服务接口
@@ -41,29 +37,29 @@ public interface CourseService {
/**
* @description 根据ID获取课程详情
* @param courseID 课程ID
* @return ResultDomain<TbCourse> 课程详情
* @return ResultDomain<CourseItemVO> 课程详情
* @author yslg
* @since 2025-10-15
*/
ResultDomain<CourseVO> getCourseById(String courseID);
ResultDomain<CourseItemVO> getCourseById(String courseID);
/**
* @description 创建课程
* @param course 课程信息
* @return ResultDomain<TbCourse> 创建结果
* @param courseItemVO 课程信息
* @return ResultDomain<CourseItemVO> 创建结果
* @author yslg
* @since 2025-10-15
*/
ResultDomain<CourseVO> createCourse(CourseVO courseVO);
ResultDomain<CourseItemVO> createCourse(CourseItemVO courseItemVO);
/**
* @description 更新课程
* @param courseVO 课程信息
* @return ResultDomain<CourseVO> 更新结果
* @param courseItemVO 课程信息
* @return ResultDomain<CourseItemVO> 更新结果
* @author yslg
* @since 2025-10-15
*/
ResultDomain<CourseVO> updateCourse(CourseVO courseVO);
ResultDomain<CourseItemVO> updateCourse(CourseItemVO courseItemVO);
/**
* @description 删除课程
@@ -185,4 +181,13 @@ public interface CourseService {
* @since 2025-10-22
*/
ResultDomain<Boolean> deleteChapterNode(String nodeID);
/**
* @description 获取课程进度
* @param courseID 课程ID
* @return ResultDomain<CourseItemVO> 课程进度
* @author yslg
* @since 2025-10-28
*/
ResultDomain<CourseItemVO> getCourseProgress(String courseID);
}

View File

@@ -12,6 +12,8 @@ import org.xyzh.common.dto.BaseDTO;
public class TbBanner extends BaseDTO {
private static final long serialVersionUID = 1L;
private String bannerID;
/**
* @description Banner标题
@@ -58,6 +60,14 @@ public class TbBanner extends BaseDTO {
*/
private String updater;
public String getBannerID() {
return bannerID;
}
public void setBannerID(String bannerID) {
this.bannerID = bannerID;
}
public String getTitle() {
return title;
}
@@ -134,6 +144,7 @@ public class TbBanner extends BaseDTO {
public String toString() {
return "TbBanner{" +
"id=" + getID() +
", bannerID='" + bannerID + '\'' +
", title='" + title + '\'' +
", imageUrl='" + imageUrl + '\'' +
", linkType=" + linkType +

View File

@@ -1,35 +0,0 @@
package org.xyzh.common.vo;
import org.xyzh.common.dto.BaseDTO;
import org.xyzh.common.dto.study.TbCourseNode;
import org.xyzh.common.dto.study.TbCourseChapter;
import java.util.ArrayList;
import java.util.List;
public class ChapterVO extends BaseDTO{
private static final long serialVersionUID = 1L;
private TbCourseChapter chapter;
private List<TbCourseNode> nodes;
public TbCourseChapter getChapter() {
return chapter;
}
public void setChapter(TbCourseChapter chapter) {
this.chapter = chapter;
}
public List<TbCourseNode> getNodes() {
return nodes;
}
public void setNodes(List<TbCourseNode> nodes) {
this.nodes = nodes;
}
public void addNode(TbCourseNode node) {
if (nodes == null) {
nodes = new ArrayList<>();
}
nodes.add(node);
}
}

View File

@@ -0,0 +1,589 @@
package org.xyzh.common.vo;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.xyzh.common.dto.BaseDTO;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.dto.study.TbCourseChapter;
import org.xyzh.common.dto.study.TbCourseNode;
import org.xyzh.common.dto.study.TbLearningRecord;
/**
* @description 课程项目VO - 包含课程和学习记录的关键信息
* @filename CourseItemVO.java
* @author yslg
* @copyright xyzh
* @since 2025-10-28
*/
public class CourseItemVO extends BaseDTO {
private static final long serialVersionUID = 1L;
// ========== 课程基本信息 ==========
/**
* @description 课程ID
*/
private String courseID;
/**
* @description 课程名称
*/
private String name;
/**
* @description 课程封面图片
*/
private String coverImage;
/**
* @description 课程描述
*/
private String description;
/**
* @description 课程时长(分钟)
*/
private Integer duration;
/**
* @description 授课老师
*/
private String teacher;
/**
* @description 课程状态0未上线 1已上线 2已下架
*/
private Integer status;
/**
* @description 浏览次数
*/
private Integer viewCount;
/**
* @description 学习人数
*/
private Integer learnCount;
/**
* @description 课程创建时间
*/
private Date createTime;
// ========== 学习记录信息 ==========
/**
* @description 学习记录ID
*/
private String recordID;
/**
* @description 学习进度0-100
*/
private BigDecimal progress;
/**
* @description 是否完成
*/
private Boolean isComplete;
/**
* @description 学习时长(秒)
*/
private Integer learningDuration;
/**
* @description 最后学习时间
*/
private Date lastLearnTime;
/**
* @description 完成时间
*/
private Date completeTime;
// ========== 章节节点信息 ==========
/**
* @description 章节ID当此对象代表章节或节点时使用
*/
private String chapterID;
/**
* @description 节点ID当此对象代表节点时使用
*/
private String nodeID;
/**
* @description 父级ID章节的父章节ID
*/
private String parentID;
/**
* @description 节点类型1视频 2文档 3音频 4图片 5链接
*/
private Integer nodeType;
/**
* @description 节点内容(富文本内容)
*/
private String content;
/**
* @description 视频URL
*/
private String videoUrl;
/**
* @description 资源ID
*/
private String resourceID;
/**
* @description 排序号
*/
private Integer orderNum;
/**
* @description 是否必修1必修 0选修
*/
private Integer isRequired;
// ========== 层级结构 ==========
/**
* @description 章节列表(课程的章节列表)
*/
private List<CourseItemVO> chapters;
/**
* @description 章节节点映射key: chapterID, value: 该章节下的节点列表)
*/
private Map<String, List<CourseItemVO>> chapterNodes;
// ========== Getters and Setters ==========
public String getCourseID() {
return courseID;
}
public void setCourseID(String courseID) {
this.courseID = courseID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCoverImage() {
return coverImage;
}
public void setCoverImage(String coverImage) {
this.coverImage = coverImage;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getDuration() {
return duration;
}
public void setDuration(Integer duration) {
this.duration = duration;
}
public String getTeacher() {
return teacher;
}
public void setTeacher(String teacher) {
this.teacher = teacher;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getViewCount() {
return viewCount;
}
public void setViewCount(Integer viewCount) {
this.viewCount = viewCount;
}
public Integer getLearnCount() {
return learnCount;
}
public void setLearnCount(Integer learnCount) {
this.learnCount = learnCount;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getRecordID() {
return recordID;
}
public void setRecordID(String recordID) {
this.recordID = recordID;
}
public BigDecimal getProgress() {
return progress;
}
public void setProgress(BigDecimal progress) {
this.progress = progress;
}
public Boolean getIsComplete() {
return isComplete;
}
public void setIsComplete(Boolean isComplete) {
this.isComplete = isComplete;
}
public Integer getLearningDuration() {
return learningDuration;
}
public void setLearningDuration(Integer learningDuration) {
this.learningDuration = learningDuration;
}
public Date getLastLearnTime() {
return lastLearnTime;
}
public void setLastLearnTime(Date lastLearnTime) {
this.lastLearnTime = lastLearnTime;
}
public Date getCompleteTime() {
return completeTime;
}
public void setCompleteTime(Date completeTime) {
this.completeTime = completeTime;
}
public String getChapterID() {
return chapterID;
}
public void setChapterID(String chapterID) {
this.chapterID = chapterID;
}
public String getNodeID() {
return nodeID;
}
public void setNodeID(String nodeID) {
this.nodeID = nodeID;
}
public String getParentID() {
return parentID;
}
public void setParentID(String parentID) {
this.parentID = parentID;
}
public Integer getNodeType() {
return nodeType;
}
public void setNodeType(Integer nodeType) {
this.nodeType = nodeType;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getVideoUrl() {
return videoUrl;
}
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
public String getResourceID() {
return resourceID;
}
public void setResourceID(String resourceID) {
this.resourceID = resourceID;
}
public Integer getOrderNum() {
return orderNum;
}
public void setOrderNum(Integer orderNum) {
this.orderNum = orderNum;
}
public Integer getIsRequired() {
return isRequired;
}
public void setIsRequired(Integer isRequired) {
this.isRequired = isRequired;
}
public List<CourseItemVO> getChapters() {
return chapters;
}
public void setChapters(List<CourseItemVO> chapters) {
this.chapters = chapters;
}
public Map<String, List<CourseItemVO>> getChapterNodes() {
return chapterNodes;
}
public void setChapterNodes(Map<String, List<CourseItemVO>> chapterNodes) {
this.chapterNodes = chapterNodes;
}
// ========== 类型转换方法 ==========
/**
* @description 转换为课程实体对象
* @return TbCourse 课程实体
*/
public TbCourse toCourse() {
TbCourse course = new TbCourse();
course.setID(this.getID());
course.setCourseID(this.courseID);
course.setName(this.name);
course.setCoverImage(this.coverImage);
course.setDescription(this.description);
course.setDuration(this.duration);
course.setTeacher(this.teacher);
course.setStatus(this.status);
course.setViewCount(this.viewCount);
course.setLearnCount(this.learnCount);
course.setCreateTime(this.createTime);
return course;
}
/**
* @description 从课程实体创建CourseItemVO
* @param course 课程实体
* @return CourseItemVO
*/
public static CourseItemVO fromCourse(TbCourse course) {
if (course == null) {
return null;
}
CourseItemVO vo = new CourseItemVO();
vo.setID(course.getID());
vo.setCourseID(course.getCourseID());
vo.setName(course.getName());
vo.setCoverImage(course.getCoverImage());
vo.setDescription(course.getDescription());
vo.setDuration(course.getDuration());
vo.setTeacher(course.getTeacher());
vo.setStatus(course.getStatus());
vo.setViewCount(course.getViewCount());
vo.setLearnCount(course.getLearnCount());
vo.setCreateTime(course.getCreateTime());
return vo;
}
/**
* @description 转换为学习记录实体对象
* @return TbLearningRecord 学习记录实体
*/
public TbLearningRecord toLearningRecord() {
TbLearningRecord record = new TbLearningRecord();
if (this.recordID != null) {
// 如果有recordID说明是从已有记录转换的需要设置ID
record.setID(this.recordID);
}
record.setCourseID(this.courseID);
record.setDuration(this.learningDuration);
record.setProgress(this.progress);
record.setIsComplete(this.isComplete);
record.setCompleteTime(this.completeTime);
record.setLastLearnTime(this.lastLearnTime);
return record;
}
/**
* @description 设置学习记录信息
* @param record 学习记录实体
*/
public void setLearningRecordInfo(TbLearningRecord record) {
if (record == null) {
return;
}
this.recordID = record.getID();
this.progress = record.getProgress();
this.isComplete = record.getIsComplete();
this.learningDuration = record.getDuration();
this.lastLearnTime = record.getLastLearnTime();
this.completeTime = record.getCompleteTime();
}
/**
* @description 从课程和学习记录创建CourseItemVO
* @param course 课程实体
* @param record 学习记录实体
* @return CourseItemVO
*/
public static CourseItemVO fromCourseAndRecord(TbCourse course, TbLearningRecord record) {
CourseItemVO vo = fromCourse(course);
if (vo != null && record != null) {
vo.setLearningRecordInfo(record);
}
return vo;
}
/**
* @description 从章节创建CourseItemVO
* @param chapter 章节实体
* @return CourseItemVO
*/
public static CourseItemVO fromChapter(TbCourseChapter chapter) {
if (chapter == null) {
return null;
}
CourseItemVO vo = new CourseItemVO();
vo.setID(chapter.getID());
vo.setChapterID(chapter.getChapterID());
vo.setCourseID(chapter.getCourseID());
vo.setParentID(chapter.getParentID());
vo.setName(chapter.getName());
vo.setDescription(chapter.getContent());
vo.setDuration(chapter.getDuration());
vo.setVideoUrl(chapter.getVideoUrl());
vo.setResourceID(chapter.getResourceID());
vo.setNodeType(chapter.getChapterType());
vo.setOrderNum(chapter.getOrderNum());
vo.setCreateTime(chapter.getCreateTime());
return vo;
}
/**
* @description 从节点创建CourseItemVO
* @param node 节点实体
* @return CourseItemVO
*/
public static CourseItemVO fromNode(TbCourseNode node) {
if (node == null) {
return null;
}
CourseItemVO vo = new CourseItemVO();
vo.setID(node.getID());
vo.setNodeID(node.getNodeID());
vo.setChapterID(node.getChapterID());
vo.setName(node.getName());
vo.setContent(node.getContent());
vo.setDuration(node.getDuration());
vo.setVideoUrl(node.getVideoUrl());
vo.setResourceID(node.getResourceID());
vo.setNodeType(node.getNodeType());
vo.setOrderNum(node.getOrderNum());
vo.setIsRequired(node.getIsRequired());
vo.setCreateTime(node.getCreateTime());
return vo;
}
/**
* @description 转换为章节实体对象
* @return TbCourseChapter 章节实体
*/
public TbCourseChapter toChapter() {
TbCourseChapter chapter = new TbCourseChapter();
chapter.setID(this.getID());
chapter.setChapterID(this.chapterID);
chapter.setCourseID(this.courseID);
chapter.setParentID(this.parentID);
chapter.setName(this.name);
chapter.setContent(this.description);
chapter.setDuration(this.duration);
chapter.setVideoUrl(this.videoUrl);
chapter.setResourceID(this.resourceID);
chapter.setChapterType(this.nodeType);
chapter.setOrderNum(this.orderNum);
return chapter;
}
/**
* @description 转换为节点实体对象
* @return TbCourseNode 节点实体
*/
public TbCourseNode toNode() {
TbCourseNode node = new TbCourseNode();
node.setID(this.getID());
node.setNodeID(this.nodeID);
node.setChapterID(this.chapterID);
node.setName(this.name);
node.setContent(this.content);
node.setDuration(this.duration);
node.setVideoUrl(this.videoUrl);
node.setResourceID(this.resourceID);
node.setNodeType(this.nodeType);
node.setOrderNum(this.orderNum);
node.setIsRequired(this.isRequired);
return node;
}
@Override
public String toString() {
return "CourseItemVO{" +
"courseID='" + courseID + '\'' +
", name='" + name + '\'' +
", coverImage='" + coverImage + '\'' +
", teacher='" + teacher + '\'' +
", duration=" + duration +
", status=" + status +
", progress=" + progress +
", isComplete=" + isComplete +
", learningDuration=" + learningDuration +
", lastLearnTime=" + lastLearnTime +
", viewCount=" + viewCount +
", learnCount=" + learnCount +
'}';
}
}

View File

@@ -1,39 +0,0 @@
package org.xyzh.common.vo;
import org.xyzh.common.dto.BaseDTO;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.dto.study.TbCourseTag;
import org.xyzh.common.vo.ChapterVO;
import java.util.List;
public class CourseVO extends BaseDTO{
private static final long serialVersionUID = 1L;
private TbCourse course;
private List<ChapterVO> courseChapters;
private List<TbCourseTag> courseTags;
public TbCourse getCourse() {
return course;
}
public void setCourse(TbCourse course) {
this.course = course;
}
public List<ChapterVO> getCourseChapters() {
return courseChapters;
}
public void setCourseChapters(List<ChapterVO> courseChapters) {
this.courseChapters = courseChapters;
}
public List<TbCourseTag> getCourseTags() {
return courseTags;
}
public void setCourseTags(List<TbCourseTag> courseTags) {
this.courseTags = courseTags;
}
}

View File

@@ -0,0 +1,37 @@
package org.xyzh.crontab.enums;
import java.util.Arrays;
import org.xyzh.crontab.task.DataBackupTask;
import org.xyzh.crontab.task.LogCleanTask;
import org.xyzh.crontab.task.SystemStatisticsTask;
public enum TaskEnums {
DATA_BACKUP("dataBackup", DataBackupTask.class),
LOG_CLEAN("logClean", LogCleanTask.class),
SystemStatistics("systemStatistics", SystemStatisticsTask.class);
private String name;
private Class<?> clazz;
TaskEnums(String name, Class<?> clazz) {
this.name = name;
this.clazz = clazz;
}
public String getName() {
return name;
}
public Class<?> getClazz() {
return clazz;
}
public static TaskEnums getByName(String name) {
return Arrays.stream(TaskEnums.values())
.filter(task -> task.getName().equals(name))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,12 @@
package org.xyzh.crontab.task.newsTask;
abstract public class NewsTask {
// 爬取网站目标
private String target;
// 爬取标题
private String title;
}

View File

@@ -6,7 +6,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.xyzh.api.news.banner.BannerService;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.dto.resource.TbBanner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @description 横幅控制器
@@ -27,16 +31,16 @@ public class BannerController {
* 获取横幅列表
*/
@GetMapping("/list")
public ResultDomain<TbBanner> getBannerList() {
return bannerService.getBannerList(null);
public ResultDomain<TbBanner> getBannerList(TbBanner filter) {
return bannerService.getBannerList(filter);
}
/**
* 根据ID获取横幅详情
*/
@GetMapping("/banner/{bannerID}")
public ResultDomain<TbBanner> getBannerById(@PathVariable String bannerID) {
return bannerService.getBannerById(bannerID);
@PostMapping("/banner/page")
public ResultDomain<TbBanner> getBannerPage(@RequestBody PageRequest<TbBanner> pageRequest) {
return bannerService.getBannerPage(pageRequest.getPageParam(), pageRequest.getFilter());
}
/**
@@ -58,36 +62,27 @@ public class BannerController {
/**
* 删除横幅
*/
@DeleteMapping("/banner/{bannerID}")
public ResultDomain<Boolean> deleteBanner(@PathVariable String bannerID) {
return bannerService.deleteBanner(bannerID);
@DeleteMapping("/banner")
public ResultDomain<Boolean> deleteBanner(@RequestBody TbBanner banner) {
return bannerService.deleteBanner(banner.getBannerID());
}
/**
* 更新横幅状态
*/
@PutMapping("/banner/{bannerID}/status")
public ResultDomain<TbBanner> updateBannerStatus(
@PathVariable String bannerID,
@RequestParam Integer status) {
return bannerService.updateBannerStatus(bannerID, status);
@PutMapping("/banner/status")
public ResultDomain<TbBanner> updateBannerStatus(@RequestBody TbBanner banner) {
return bannerService.updateBannerStatus(banner.getBannerID(), banner.getStatus());
}
/**
* 更新横幅排序
* 获取首页横幅列表
*/
@PutMapping("/banner/{bannerID}/order")
public ResultDomain<TbBanner> updateBannerOrder(
@PathVariable String bannerID,
@RequestParam Integer orderNum) {
return bannerService.updateBannerOrder(bannerID, orderNum);
@GetMapping("/home")
public ResultDomain<TbBanner> getHomeBannerList() {
return bannerService.selectHomeBanners();
}
/**
* 获取活跃横幅
*/
@GetMapping("/active")
public ResultDomain<TbBanner> getActiveBanners(@RequestParam(required = false) Integer limit) {
return bannerService.getActiveBanners(limit);
}
}

View File

@@ -27,6 +27,19 @@ public interface BannerMapper extends BaseMapper<TbBanner> {
*/
List<TbBanner> selectBanners(TbBanner filter);
List<TbBanner> selectBannersLimit(@Param("filter") TbBanner filter, @Param("limit") Integer limit);
/**
* @description 分页查询Banner
* @param filter 过滤条件
* @param pageParam 分页参数
* @return List<TbBanner> Banner列表
* @author yslg
* @since 2025-10-15
*/
List<TbBanner> selectBannersPage(@Param("filter") TbBanner filter, @Param("pageParam") PageParam pageParam);
/**
* @description 根据Banner ID查询Banner信息
* @param bannerId Banner ID
@@ -117,16 +130,6 @@ public interface BannerMapper extends BaseMapper<TbBanner> {
*/
int batchDeleteBanners(@Param("ids") List<String> ids);
/**
* @description 分页查询Banner
* @param filter 过滤条件
* @param pageParam 分页参数
* @return List<TbBanner> Banner列表
* @author yslg
* @since 2025-10-15
*/
List<TbBanner> selectBannersPage(@Param("filter") TbBanner filter, @Param("pageParam") PageParam pageParam);
/**
* @description 统计Banner总数
* @param filter 过滤条件

View File

@@ -11,6 +11,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.dto.resource.TbBanner;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.news.mapper.BannerMapper;
@@ -32,49 +34,27 @@ public class NCBannerServiceImpl implements BannerService {
private BannerMapper bannerMapper;
@Override
public ResultDomain<TbBanner> getBannerList(Integer status) {
public ResultDomain<TbBanner> getBannerList(TbBanner filter) {
ResultDomain<TbBanner> resultDomain = new ResultDomain<>();
try {
List<TbBanner> list;
if (status != null) {
list = bannerMapper.selectByStatus(status);
} else {
TbBanner filter = new TbBanner();
list = bannerMapper.selectBanners(filter);
}
resultDomain.success("获取横幅列表成功", list);
return resultDomain;
} catch (Exception e) {
logger.error("获取横幅列表异常: {}", e.getMessage(), e);
resultDomain.fail("获取横幅列表失败: " + e.getMessage());
return resultDomain;
}
List<TbBanner> list = bannerMapper.selectBanners(filter);
resultDomain.success("获取横幅列表成功", list);
return resultDomain;
}
@Override
public ResultDomain<TbBanner> getBannerById(String bannerID) {
public ResultDomain<TbBanner> getBannerPage(PageParam pageParam,TbBanner filter) {
ResultDomain<TbBanner> resultDomain = new ResultDomain<>();
try {
// 参数验证
if (!StringUtils.hasText(bannerID)) {
resultDomain.fail("横幅ID不能为空");
return resultDomain;
}
List<TbBanner> list = bannerMapper.selectBannersPage(filter, pageParam);
PageDomain<TbBanner> pageDomain = new PageDomain<>();
int total = (int)bannerMapper.countBanners(filter);
pageParam.setTotalElements(total);
pageParam.setTotalPages( (int)Math.ceil((double)total / pageParam.getPageSize()));
pageDomain.setDataList(list);
pageDomain.setPageParam(pageParam);
// 查询横幅
TbBanner banner = bannerMapper.selectByBannerId(bannerID);
if (banner == null || banner.getDeleted()) {
resultDomain.fail("横幅不存在");
return resultDomain;
}
resultDomain.success("获取横幅详情成功", banner);
return resultDomain;
} catch (Exception e) {
logger.error("获取横幅详情异常: {}", e.getMessage(), e);
resultDomain.fail("获取横幅详情失败: " + e.getMessage());
return resultDomain;
}
resultDomain.success("获取横幅列表成功", pageDomain);
return resultDomain;
}
@Override
@@ -103,7 +83,7 @@ public class NCBannerServiceImpl implements BannerService {
if (banner.getID() == null) {
banner.setID(IDUtils.generateID());
}
banner.setBannerID(IDUtils.generateID());
banner.setCreateTime(new Date());
banner.setUpdateTime(new Date());
banner.setDeleted(false);
@@ -139,13 +119,13 @@ public class NCBannerServiceImpl implements BannerService {
ResultDomain<TbBanner> resultDomain = new ResultDomain<>();
try {
// 参数验证
if (banner == null || !StringUtils.hasText(banner.getID())) {
if (banner == null || !StringUtils.hasText(banner.getBannerID())) {
resultDomain.fail("横幅ID不能为空");
return resultDomain;
}
// 检查横幅是否存在
TbBanner existing = bannerMapper.selectById(banner.getID());
TbBanner existing = bannerMapper.selectByBannerId(banner.getBannerID());
if (existing == null || existing.getDeleted()) {
resultDomain.fail("横幅不存在");
return resultDomain;
@@ -153,7 +133,7 @@ public class NCBannerServiceImpl implements BannerService {
// 如果修改了标题,检查标题是否已被使用
if (StringUtils.hasText(banner.getTitle()) && !banner.getTitle().equals(existing.getTitle())) {
int count = bannerMapper.countByTitle(banner.getTitle(), banner.getID());
int count = bannerMapper.countByTitle(banner.getTitle(), banner.getBannerID());
if (count > 0) {
resultDomain.fail("横幅标题已存在");
return resultDomain;
@@ -166,9 +146,9 @@ public class NCBannerServiceImpl implements BannerService {
// 更新数据库
int result = bannerMapper.updateBanner(banner);
if (result > 0) {
logger.info("更新横幅成功: {}", banner.getID());
logger.info("更新横幅成功: {}", banner.getBannerID());
// 重新查询返回完整数据
TbBanner updated = bannerMapper.selectById(banner.getID());
TbBanner updated = bannerMapper.selectByBannerId(banner.getBannerID());
resultDomain.success("更新横幅成功", updated);
return resultDomain;
} else {
@@ -247,7 +227,7 @@ public class NCBannerServiceImpl implements BannerService {
if (result > 0) {
logger.info("更新横幅状态成功: {}", bannerID);
// 重新查询返回完整数据
TbBanner updated = bannerMapper.selectById(banner.getID());
TbBanner updated = bannerMapper.selectByBannerId(banner.getBannerID());
resultDomain.success("更新横幅状态成功", updated);
return resultDomain;
} else {
@@ -291,7 +271,7 @@ public class NCBannerServiceImpl implements BannerService {
if (result > 0) {
logger.info("更新横幅排序成功: {}", bannerID);
// 重新查询返回完整数据
TbBanner updated = bannerMapper.selectById(banner.getID());
TbBanner updated = bannerMapper.selectByBannerId(banner.getBannerID());
resultDomain.success("更新横幅排序成功", updated);
return resultDomain;
} else {
@@ -377,4 +357,15 @@ public class NCBannerServiceImpl implements BannerService {
return resultDomain;
}
}
@Override
public ResultDomain<TbBanner> selectHomeBanners() {
ResultDomain<TbBanner> resultDomain = new ResultDomain<>();
TbBanner filter = new TbBanner();
filter.setStatus(1);
List<TbBanner> list = bannerMapper.selectBannersLimit(filter, 5);
resultDomain.success("获取首页横幅列表成功", list);
return resultDomain;
}
}

View File

@@ -13,9 +13,11 @@ import org.springframework.util.StringUtils;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.dto.resource.TbResourceTag;
import org.xyzh.common.dto.resource.TbTag;
import org.xyzh.common.dto.user.TbSysUser;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.news.mapper.ResourceTagMapper;
import org.xyzh.news.mapper.TagMapper;
import org.xyzh.system.utils.LoginUtil;
import org.xyzh.api.news.tag.TagService;
/**
@@ -89,39 +91,27 @@ public class NCTagServiceImpl implements TagService {
@Transactional(rollbackFor = Exception.class)
public ResultDomain<TbTag> updateTag(TbTag tag) {
ResultDomain<TbTag> resultDomain = new ResultDomain<>();
TbSysUser user = LoginUtil.getCurrentUser();
if (user == null) {
resultDomain.fail("用户未登录");
return resultDomain;
}
try {
// 参数验证
if (tag == null || !StringUtils.hasText(tag.getID())) {
if (tag == null || !StringUtils.hasText(tag.getTagID())) {
resultDomain.fail("标签ID不能为空");
return resultDomain;
}
// 检查标签是否存在
TbTag existingTag = tagMapper.selectById(tag.getID());
if (existingTag == null || existingTag.getDeleted()) {
resultDomain.fail("标签不存在");
return resultDomain;
}
// 检查标签名称是否重复(排除自身,同类型下)
if (StringUtils.hasText(tag.getName())) {
Integer tagType = tag.getTagType() != null ? tag.getTagType() : existingTag.getTagType();
int count = tagMapper.countByNameAndType(tag.getName(), tagType, tag.getID());
if (count > 0) {
resultDomain.fail("该类型下标签名称已存在");
return resultDomain;
}
}
// 更新时间
tag.setUpdater(user.getID());
tag.setUpdateTime(new Date());
// 更新数据库
int result = tagMapper.updateTag(tag);
if (result > 0) {
logger.info("更新标签成功: {}", tag.getID());
logger.info("更新标签成功: {}", tag.getTagID());
// 重新查询返回完整数据
TbTag updated = tagMapper.selectById(tag.getID());
TbTag updated = tagMapper.selectByTagId(tag.getTagID());
resultDomain.success("更新标签成功", updated);
return resultDomain;
} else {

View File

@@ -5,6 +5,7 @@
<!-- 基础结果映射 -->
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.resource.TbBanner">
<id column="id" property="id" jdbcType="VARCHAR"/>
<result column="banner_id" property="bannerID" jdbcType="VARCHAR"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="image_url" property="imageUrl" jdbcType="VARCHAR"/>
<result column="link_type" property="linkType" jdbcType="INTEGER"/>
@@ -22,7 +23,7 @@
<!-- 基础字段 -->
<sql id="Base_Column_List">
id, title, image_url, link_type, link_id, link_url, order_num, status,
id, banner_id, title, image_url, link_type, link_id, link_url, order_num, status,
creator, updater, create_time, update_time, delete_time, deleted
</sql>
@@ -30,6 +31,9 @@
<sql id="Where_Clause">
<where>
deleted = 0
<if test="bannerID != null and bannerID != ''">
AND banner_id = #{bannerID}
</if>
<if test="title != null and title != ''">
AND title LIKE CONCAT('%', #{title}, '%')
</if>
@@ -44,6 +48,26 @@
</if>
</where>
</sql>
<sql id="Filter_Clause">
<where>
deleted = 0
<if test="filter.bannerID != null and filter.bannerID != ''">
AND banner_id = #{filter.bannerID}
</if>
<if test="filter.title != null and filter.title != ''">
AND title LIKE CONCAT('%', #{filter.title}, '%')
</if>
<if test="filter.linkType != null">
AND link_type = #{filter.linkType}
</if>
<if test="filter.linkID != null and filter.linkID != ''">
AND link_id = #{filter.linkID}
</if>
<if test="filter.status != null">
AND status = #{filter.status}
</if>
</where>
</sql>
<!-- selectBanners -->
<select id="selectBanners" resultMap="BaseResultMap">
@@ -54,12 +78,21 @@
ORDER BY order_num ASC, create_time DESC
</select>
<select id="selectBannersLimit" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM tb_banner
<include refid="Filter_Clause"/>
ORDER BY order_num ASC, create_time DESC
LIMIT #{limit}
</select>
<!-- 根据Banner ID查询Banner信息 -->
<select id="selectByBannerId" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM tb_banner
WHERE id = #{bannerId} AND deleted = 0
WHERE banner_id = #{bannerID} AND deleted = 0
</select>
<!-- 根据状态查询Banner列表 -->
@@ -95,18 +128,18 @@
FROM tb_banner
WHERE title = #{title} AND deleted = 0
<if test="excludeId != null and excludeId != ''">
AND id != #{excludeId}
AND banner_id != #{excludeId}
</if>
</select>
<!-- 插入Banner -->
<insert id="insertBanner" parameterType="org.xyzh.common.dto.resource.TbBanner">
INSERT INTO tb_banner (
id, title, image_url, link_type, link_id, link_url, order_num, status,
creator, updater, create_time, update_time, delete_time, deleted
id, banner_id, title, image_url, link_type, link_id, link_url, order_num, status,
creator, create_time
) VALUES (
#{id}, #{title}, #{imageUrl}, #{linkType}, #{linkID}, #{linkUrl}, #{orderNum}, #{status},
#{creator}, #{updater}, #{createTime}, #{updateTime}, #{deleteTime}, #{deleted}
#{id}, #{bannerID}, #{title}, #{imageUrl}, #{linkType}, #{linkID}, #{linkUrl}, #{orderNum}, #{status},
#{creator}, #{createTime}
)
</insert>
@@ -114,6 +147,9 @@
<update id="updateBanner" parameterType="org.xyzh.common.dto.resource.TbBanner">
UPDATE tb_banner
<set>
<if test="bannerID != null and bannerID != ''">
banner_id = #{bannerID},
</if>
<if test="title != null and title != ''">
title = #{title},
</if>
@@ -148,24 +184,24 @@
deleted = #{deleted},
</if>
</set>
WHERE id = #{id}
WHERE banner_id = #{bannerID}
</update>
<!-- 删除Banner -->
<delete id="deleteBanner" parameterType="org.xyzh.common.dto.resource.TbBanner">
DELETE FROM tb_banner
WHERE id = #{id}
WHERE banner_id = #{bannerID}
</delete>
<!-- 批量插入Banner -->
<insert id="batchInsertBanners" parameterType="java.util.List">
INSERT INTO tb_banner (
id, title, image_url, link_type, link_id, link_url, order_num, status,
id, banner_id, title, image_url, link_type, link_id, link_url, order_num, status,
creator, updater, create_time, update_time, delete_time, deleted
) VALUES
<foreach collection="bannerList" item="item" separator=",">
(
#{item.id}, #{item.title}, #{item.imageUrl}, #{item.linkType}, #{item.linkID},
#{item.id}, #{item.bannerID}, #{item.title}, #{item.imageUrl}, #{item.linkType}, #{item.linkID},
#{item.linkUrl}, #{item.orderNum}, #{item.status}, #{item.creator}, #{item.updater},
#{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
)
@@ -175,9 +211,9 @@
<!-- 批量删除Banner -->
<delete id="batchDeleteBanners">
DELETE FROM tb_banner
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
WHERE banner_id IN
<foreach collection="ids" item="bannerID" open="(" separator="," close=")">
#{bannerID}
</foreach>
</delete>
@@ -186,7 +222,7 @@
SELECT
<include refid="Base_Column_List" />
FROM tb_banner
<include refid="Where_Clause" />
<include refid="Filter_Clause" />
ORDER BY order_num ASC, create_time DESC
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
</select>
@@ -195,7 +231,7 @@
<select id="countBanners" resultType="long">
SELECT COUNT(1)
FROM tb_banner
<include refid="Where_Clause" />
<include refid="Filter_Clause" />
</select>
</mapper>

View File

@@ -10,11 +10,11 @@ import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.dto.study.TbCourseChapter;
import org.xyzh.common.dto.study.TbCourseNode;
import org.xyzh.common.dto.study.TbLearningRecord;
import org.xyzh.common.vo.ChapterVO;
import org.xyzh.common.vo.CourseVO;
import org.xyzh.common.vo.CourseItemVO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.GetMapping;
/**
@@ -52,24 +52,30 @@ public class CourseController {
* 根据ID获取课程详情
*/
@GetMapping("/{courseID}")
public ResultDomain<CourseVO> getCourseById(@PathVariable("courseID") String courseID) {
public ResultDomain<CourseItemVO> getCourseById(@PathVariable("courseID") String courseID) {
return courseService.getCourseById(courseID);
}
@GetMapping("/{courseID}/progress")
public ResultDomain<CourseItemVO> getCourseProgress(@PathVariable("courseID") String courseID) {
return courseService.getCourseProgress(courseID);
}
/**
* 创建课程
*/
@PostMapping("/course")
public ResultDomain<CourseVO> createCourse(@RequestBody CourseVO courseVO) {
return courseService.createCourse(courseVO);
public ResultDomain<CourseItemVO> createCourse(@RequestBody CourseItemVO courseItemVO) {
return courseService.createCourse(courseItemVO);
}
/**
* 更新课程基本信息
*/
@PutMapping("/course")
public ResultDomain<CourseVO> updateCourse(@RequestBody CourseVO courseVO) {
return courseService.updateCourse(courseVO);
public ResultDomain<CourseItemVO> updateCourse(@RequestBody CourseItemVO courseItemVO) {
return courseService.updateCourse(courseItemVO);
}
/**

View File

@@ -88,8 +88,8 @@ public class LearningTaskController {
* 删除任务
*/
@DeleteMapping("/task")
public ResultDomain<Boolean> deleteTask(@PathVariable("taskID") String taskID) {
return learningTaskService.deleteTask(taskID);
public ResultDomain<Boolean> deleteTask(@RequestBody TbLearningTask task) {
return learningTaskService.deleteTask(task.getTaskID());
}
/**

View File

@@ -5,6 +5,7 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.vo.CourseItemVO;
import java.util.List;
@@ -181,4 +182,14 @@ public interface CourseMapper extends BaseMapper<TbCourse> {
* @since 2025-10-15
*/
int incrementViewCount(@Param("courseID") String courseID);
/**
* @description 增加课程学习人数
* @param courseID 课程ID
* @param count 增加人数
* @return int 影响行数
* @author yslg
* @since 2025-10-15
*/
int incrementLearnCount(@Param("courseID") String courseID, @Param("count") int count);
}

View File

@@ -5,6 +5,7 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.dto.study.TbCourseNode;
import org.xyzh.common.vo.CourseItemVO;
import java.util.List;
@@ -35,6 +36,16 @@ public interface CourseNodeMapper extends BaseMapper<TbCourseNode> {
* @since 2025-10-21
*/
List<TbCourseNode> selectCourseNodesByChapterIDs(@Param("chapterIDs") List<String> chapterIDs);
/**
* @description 查询节点进度
* @param chapterIDs 章节ID列表
* @param userID 用户ID可选传null则不关联学习记录
* @return List<CourseItemVO> 节点进度列表
* @author yslg
* @since 2025-10-28
*/
List<CourseItemVO> selectNodesProgress(@Param("chapterIDs") List<String> chapterIDs, @Param("userID") String userID);
/**
* @description 根据节点ID查询节点信息
* @param nodeId 节点ID

View File

@@ -20,14 +20,10 @@ import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.dto.study.TbCourseChapter;
import org.xyzh.common.dto.study.TbCourseNode;
import org.xyzh.common.dto.study.TbCourseTag;
import org.xyzh.common.dto.study.TbLearningRecord;
import org.xyzh.common.dto.user.TbSysUser;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.common.vo.ChapterVO;
import org.xyzh.common.vo.CourseVO;
import org.xyzh.common.vo.CourseItemVO;
import org.xyzh.study.mapper.CourseMapper;
import org.xyzh.study.mapper.CourseTagMapper;
import org.xyzh.study.mapper.CourseChapterMapper;
import org.xyzh.study.mapper.CourseNodeMapper;
import org.xyzh.study.service.SCCourseService;
@@ -51,9 +47,6 @@ public class SCCourseServiceImpl implements SCCourseService {
@Autowired
private CourseChapterMapper courseChapterMapper;
@Autowired
private CourseTagMapper courseTagMapper;
@Autowired
private CourseNodeMapper courseNodeMapper;
@@ -81,108 +74,133 @@ public class SCCourseServiceImpl implements SCCourseService {
}
@Override
public ResultDomain<CourseVO> getCourseById(String courseID) {
ResultDomain<CourseVO> resultDomain = new ResultDomain<>();
public ResultDomain<CourseItemVO> getCourseById(String courseID) {
ResultDomain<CourseItemVO> resultDomain = new ResultDomain<>();
// 查询课程
TbCourse course = courseMapper.selectByCourseId(courseID);
// 查询标签
List<TbCourseTag> tags = courseTagMapper.selectByCourseId(courseID);
CourseVO courseVO = new CourseVO();
courseVO.setCourse(course);
courseVO.setCourseTags(tags);
if (course == null) {
resultDomain.fail("课程不存在");
return resultDomain;
}
// 从课程实体创建CourseItemVO
CourseItemVO courseItemVO = CourseItemVO.fromCourse(course);
// 查询课程章节
TbCourseChapter filter = new TbCourseChapter();
filter.setCourseID(courseID);
List<TbCourseChapter> chapters = courseChapterMapper.selectCourseChapters(filter);
// 查询子节点
if (chapters.size() > 0) {
List<String> chapterIDs = chapters.stream().map(TbCourseChapter::getChapterID).collect(Collectors.toList());
// 查询并构建章节及节点结构
if (!chapters.isEmpty()) {
List<String> chapterIDs = chapters.stream()
.map(TbCourseChapter::getChapterID)
.collect(Collectors.toList());
// 查询所有节点
List<TbCourseNode> nodes = courseNodeMapper.selectCourseNodesByChapterIDs(chapterIDs);
Map<String, List<TbCourseNode>> nodesMap = nodes.stream().collect(Collectors.groupingBy(TbCourseNode::getChapterID));
List<ChapterVO> chapterVOs = chapters.stream().map(chapter -> {
ChapterVO chapterVO = new ChapterVO();
chapterVO.setChapter(chapter);
chapterVO.setNodes(nodesMap.get(chapter.getChapterID()));
return chapterVO;
}).collect(Collectors.toList());
courseVO.setCourseChapters(chapterVOs);
// 转换章节为CourseItemVO列表
List<CourseItemVO> chapterVOs = chapters.stream()
.map(CourseItemVO::fromChapter)
.collect(Collectors.toList());
// 转换节点为CourseItemVO并按章节ID分组
Map<String, List<CourseItemVO>> nodesMap = nodes.stream()
.map(CourseItemVO::fromNode)
.collect(Collectors.groupingBy(CourseItemVO::getChapterID));
// 设置章节列表和章节节点映射
courseItemVO.setChapters(chapterVOs);
courseItemVO.setChapterNodes(nodesMap);
}
resultDomain.success("获取课程详情成功", courseVO);
resultDomain.success("获取课程详情成功", courseItemVO);
return resultDomain;
}
@Override
public ResultDomain<CourseVO> createCourse(CourseVO courseVO) {
ResultDomain<CourseVO> resultDomain = new ResultDomain<>();
public ResultDomain<CourseItemVO> createCourse(CourseItemVO courseItemVO) {
ResultDomain<CourseItemVO> resultDomain = new ResultDomain<>();
TbSysUser user = LoginUtil.getCurrentUser();
if (user == null) {
resultDomain.fail("请先登录");
return resultDomain;
}
TbCourse course = courseVO.getCourse();
// 转换为课程实体并保存
TbCourse course = courseItemVO.toCourse();
String courseID = IDUtils.generateID();
course.setID(IDUtils.generateID());
course.setCreator(user.getID());
course.setCourseID(courseID);
Date now = new Date();
course.setCreateTime(now);
course.setStatus(0);
if (course.getStatus() == null) {
course.setStatus(0);
}
courseMapper.insertCourse(course);
courseItemVO.setCourseID(courseID);
List<ChapterVO> courseChapters = courseVO.getCourseChapters();
List<TbCourseChapter> chapters = new ArrayList<>();
List<TbCourseNode> nodes = new ArrayList<>();
int length = courseChapters.size();
for (int i=0; i<length; i++) {
ChapterVO chapterVO = courseChapters.get(i);
TbCourseChapter chapter = chapterVO.getChapter();
List<TbCourseNode> nodesList = chapterVO.getNodes();
// 处理章节和节点
List<CourseItemVO> chapterVOs = courseItemVO.getChapters();
if (chapterVOs != null && !chapterVOs.isEmpty()) {
List<TbCourseChapter> chapters = new ArrayList<>();
List<TbCourseNode> allNodes = new ArrayList<>();
for (int i = 0; i < chapterVOs.size(); i++) {
CourseItemVO chapterVO = chapterVOs.get(i);
TbCourseChapter chapter = chapterVO.toChapter();
String chapterID = IDUtils.generateID();
chapter.setID(IDUtils.generateID());
chapter.setChapterID(chapterID);
chapter.setCourseID(courseID);
chapter.setCreator(user.getID());
chapter.setCreateTime(now);
chapter.setOrderNum(i);
chapters.add(chapter);
// 更新chapterVO中的ID
chapterVO.setChapterID(chapterID);
chapter.setCourseID(courseID);
String chapterID = IDUtils.generateID();
chapter.setID(IDUtils.generateID());
chapter.setChapterID(chapterID);
chapter.setCreator(user.getID());
chapter.setCreateTime(now);
chapter.setOrderNum(i);
chapters.add(chapter);
for (int j=0; j<nodesList.size(); j++) {
TbCourseNode node = nodesList.get(j);
node.setNodeID(IDUtils.generateID());
node.setChapterID(chapterID);
node.setCreator(user.getID());
node.setCreateTime(now);
nodes.add(node);
// 处理该章节的节点
List<CourseItemVO> nodeVOs = chapterVO.getChapters(); // 节点存储在chapters字段中
if (nodeVOs != null && !nodeVOs.isEmpty()) {
for (int j = 0; j < nodeVOs.size(); j++) {
CourseItemVO nodeVO = nodeVOs.get(j);
TbCourseNode node = nodeVO.toNode();
String nodeID = IDUtils.generateID();
node.setID(IDUtils.generateID());
node.setNodeID(nodeID);
node.setChapterID(chapterID);
node.setCreator(user.getID());
node.setCreateTime(now);
node.setOrderNum(j);
allNodes.add(node);
// 更新nodeVO中的ID
nodeVO.setNodeID(nodeID);
}
}
}
if (!chapters.isEmpty()) {
courseChapterMapper.batchInsertCourseChapters(chapters);
}
if (!allNodes.isEmpty()) {
courseNodeMapper.batchInsertCourseNodes(allNodes);
}
}
courseChapterMapper.batchInsertCourseChapters(chapters);
courseNodeMapper.batchInsertCourseNodes(nodes);
List<TbCourseTag> courseTags = courseVO.getCourseTags();
length = courseTags.size();
if (length > 0) {
for (int i=0; i<length; i++) {
TbCourseTag tag = courseTags.get(i);
tag.setCourseID(courseID);
tag.setTagID(IDUtils.generateID());
tag.setCreator(user.getID());
tag.setCreateTime(now);
}
courseTagMapper.batchInsertCourseTags(courseTags);
}
resultDomain.success("创建课程成功",courseVO);
resultDomain.success("创建课程成功", courseItemVO);
return resultDomain;
}
@Override
public ResultDomain<CourseVO> updateCourse(CourseVO courseVO) {
ResultDomain<CourseVO> resultDomain = new ResultDomain<>();
public ResultDomain<CourseItemVO> updateCourse(CourseItemVO courseItemVO) {
ResultDomain<CourseItemVO> resultDomain = new ResultDomain<>();
TbSysUser user = LoginUtil.getCurrentUser();
if (user == null) {
@@ -190,8 +208,7 @@ public class SCCourseServiceImpl implements SCCourseService {
return resultDomain;
}
TbCourse course = courseVO.getCourse();
String courseID = course.getCourseID();
String courseID = courseItemVO.getCourseID();
if (courseID == null || courseID.isEmpty()) {
resultDomain.fail("课程ID不能为空");
@@ -199,12 +216,14 @@ public class SCCourseServiceImpl implements SCCourseService {
}
// 1. 更新课程基本信息
TbCourse course = courseItemVO.toCourse();
course.setUpdater(user.getID());
course.setUpdateTime(new Date());
Date now = new Date();
course.setUpdateTime(now);
courseMapper.updateCourse(course);
// 2. 处理章节和节点
List<ChapterVO> newChapterVOs = courseVO.getCourseChapters();
List<CourseItemVO> newChapterVOs = courseItemVO.getChapters();
if (newChapterVOs == null) {
newChapterVOs = new ArrayList<>();
}
@@ -235,12 +254,11 @@ public class SCCourseServiceImpl implements SCCourseService {
List<TbCourseNode> nodesToUpdate = new ArrayList<>();
Set<String> newChapterIDs = new HashSet<>();
Date now = new Date();
// 遍历新的章节
for (int i = 0; i < newChapterVOs.size(); i++) {
ChapterVO chapterVO = newChapterVOs.get(i);
TbCourseChapter chapter = chapterVO.getChapter();
CourseItemVO chapterVO = newChapterVOs.get(i);
TbCourseChapter chapter = chapterVO.toChapter();
String chapterID = chapter.getChapterID();
chapter.setCourseID(courseID);
@@ -266,9 +284,9 @@ public class SCCourseServiceImpl implements SCCourseService {
newChapterIDs.add(chapterID);
// 处理该章节的节点
List<TbCourseNode> newNodes = chapterVO.getNodes();
if (newNodes == null) {
newNodes = new ArrayList<>();
List<CourseItemVO> newNodeVOs = chapterVO.getChapters(); // 节点存储在chapters字段中
if (newNodeVOs == null) {
newNodeVOs = new ArrayList<>();
}
List<TbCourseNode> existingNodesForChapter = existingNodesMap.getOrDefault(chapterID, new ArrayList<>());
@@ -278,8 +296,9 @@ public class SCCourseServiceImpl implements SCCourseService {
Set<String> newNodeIDs = new HashSet<>();
// 遍历新的节点
for (int j = 0; j < newNodes.size(); j++) {
TbCourseNode node = newNodes.get(j);
for (int j = 0; j < newNodeVOs.size(); j++) {
CourseItemVO nodeVO = newNodeVOs.get(j);
TbCourseNode node = nodeVO.toNode();
String nodeID = node.getNodeID();
node.setChapterID(chapterID);
@@ -349,50 +368,7 @@ public class SCCourseServiceImpl implements SCCourseService {
}
}
// 3. 处理标签
List<TbCourseTag> newTags = courseVO.getCourseTags();
if (newTags == null) {
newTags = new ArrayList<>();
}
// 获取现有标签
List<TbCourseTag> existingTags = courseTagMapper.selectByCourseId(courseID);
Map<String, TbCourseTag> existingTagMap = existingTags.stream()
.collect(Collectors.toMap(TbCourseTag::getTagID, tag -> tag));
Set<String> newTagIDs = new HashSet<>();
List<TbCourseTag> tagsToInsert = new ArrayList<>();
// 处理新标签
for (TbCourseTag tag : newTags) {
String tagID = tag.getTagID();
if (tagID == null || tagID.isEmpty() || !existingTagMap.containsKey(tagID)) {
// 新增标签
tag.setID(IDUtils.generateID());
tag.setCourseID(courseID);
tag.setCreator(user.getID());
tag.setCreateTime(now);
tagsToInsert.add(tag);
} else {
newTagIDs.add(tagID);
}
}
// 找出要删除的标签
List<String> tagIDsToDelete = existingTagMap.keySet().stream()
.filter(id -> !newTagIDs.contains(id))
.collect(Collectors.toList());
if (!tagIDsToDelete.isEmpty()) {
courseTagMapper.batchDeleteCourseTags(tagIDsToDelete);
}
if (!tagsToInsert.isEmpty()) {
courseTagMapper.batchInsertCourseTags(tagsToInsert);
}
resultDomain.success("更新课程成功", courseVO);
resultDomain.success("更新课程成功", courseItemVO);
return resultDomain;
}
@@ -544,4 +520,57 @@ public class SCCourseServiceImpl implements SCCourseService {
return resultDomain;
}
}
@Override
public ResultDomain<CourseItemVO> getCourseProgress(String courseID) {
ResultDomain<CourseItemVO> resultDomain = new ResultDomain<>();
// 获取当前用户
TbSysUser user = LoginUtil.getCurrentUser();
if (user == null) {
resultDomain.fail("用户未登录");
return resultDomain;
}
// 查询课程
TbCourse course = courseMapper.selectByCourseId(courseID);
if (course == null) {
resultDomain.fail("课程不存在");
return resultDomain;
}
// 从课程实体创建CourseItemVO
CourseItemVO courseItemVO = CourseItemVO.fromCourse(course);
// 查询课程章节
TbCourseChapter filter = new TbCourseChapter();
filter.setCourseID(courseID);
List<TbCourseChapter> chapters = courseChapterMapper.selectCourseChapters(filter);
// 查询并构建章节及节点结构(带进度)
if (!chapters.isEmpty()) {
List<String> chapterIDs = chapters.stream()
.map(TbCourseChapter::getChapterID)
.collect(Collectors.toList());
// 查询带进度的节点传入用户ID
List<CourseItemVO> nodesWithProgress = courseNodeMapper.selectNodesProgress(chapterIDs, user.getID());
// 转换章节为CourseItemVO列表
List<CourseItemVO> chapterVOs = chapters.stream()
.map(CourseItemVO::fromChapter)
.collect(Collectors.toList());
// 按章节ID分组节点
Map<String, List<CourseItemVO>> nodesMap = nodesWithProgress.stream()
.collect(Collectors.groupingBy(CourseItemVO::getChapterID));
// 设置章节列表和章节节点映射
courseItemVO.setChapters(chapterVOs);
courseItemVO.setChapterNodes(nodesMap);
}
resultDomain.success("获取课程进度成功", courseItemVO);
return resultDomain;
}
}

View File

@@ -25,6 +25,7 @@ import org.xyzh.common.vo.TaskItemVO;
import org.xyzh.common.vo.TaskVO;
import org.xyzh.study.mapper.LearningTaskMapper;
import org.xyzh.study.mapper.TaskUserMapper;
import org.xyzh.study.mapper.CourseMapper;
import org.xyzh.system.utils.LoginUtil;
import org.xyzh.study.mapper.TaskItemMapper;
import org.xyzh.api.study.task.LearningTaskService;
@@ -48,6 +49,9 @@ public class SCLearningTaskServiceImpl implements LearningTaskService {
@Autowired
private TaskUserMapper taskUserMapper;
@Autowired
private CourseMapper courseMapper;
@Autowired
private TaskItemMapper taskItemMapper;
@@ -82,7 +86,8 @@ public class SCLearningTaskServiceImpl implements LearningTaskService {
taskUsers.add(taskUser);
}
int result = taskUserMapper.batchInsertTaskUsers(taskUsers);
if (result > 0) {
int learnCount = courseMapper.incrementLearnCount(taskID, userIDs.size());
if (result > 0 && learnCount > 0) {
resultDomain.success("添加任务用户成功", taskUsers);
return resultDomain;
} else {
@@ -181,6 +186,10 @@ public class SCLearningTaskServiceImpl implements LearningTaskService {
item.setCreateTime(now);
});
taskUserMapper.batchInsertTaskUsers(taskUsers);
for(TbTaskItem item : taskCourses) {
int learnCount = courseMapper.incrementLearnCount(item.getItemID(), taskUsers.size());
}
resultDomain.success("创建任务成功", taskVO);
return resultDomain;
@@ -349,6 +358,7 @@ public class SCLearningTaskServiceImpl implements LearningTaskService {
if (!usersToInsert.isEmpty()) {
taskUserMapper.batchInsertTaskUsers(usersToInsert);
int learnCount = courseMapper.incrementLearnCount(taskID, usersToInsert.size());
}
resultDomain.success("更新任务成功", taskVO);
@@ -357,8 +367,17 @@ public class SCLearningTaskServiceImpl implements LearningTaskService {
@Override
public ResultDomain<Boolean> deleteTask(String taskID) {
// TODO Auto-generated method stub
return null;
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
TbLearningTask filter = new TbLearningTask();
filter.setTaskID(taskID);
int result = learningTaskMapper.deleteLearningTask(filter);
if (result > 0) {
resultDomain.success("删除任务成功", true);
return resultDomain;
} else {
resultDomain.fail("删除任务失败");
return resultDomain;
}
}
@Override

View File

@@ -184,7 +184,7 @@
teacher, status, view_count, learn_count, order_num, creator, create_time
) VALUES (
#{id}, #{courseID}, #{name}, #{coverImage}, #{description}, #{content}, #{duration},
#{teacher}, #{status}, #{viewCount}, #{learnCount}, #{orderNum}, #{creator},#{createTime}
#{teacher}, #{status}, 0, 0, #{orderNum}, #{creator},#{createTime}
)
</insert>
@@ -248,15 +248,14 @@
<insert id="batchInsertCourses" parameterType="java.util.List">
INSERT INTO tb_course (
id, course_id, name, cover_image, description, content, duration,
teacher, status, view_count, learn_count, order_num, creator, updater,
create_time, update_time, delete_time, deleted
teacher, status, view_count, learn_count, order_num, creator,
create_time, delete_time, deleted
) VALUES
<foreach collection="courseList" item="item" separator=",">
(
#{item.id}, #{item.courseID}, #{item.name}, #{item.coverImage}, #{item.description},
#{item.content}, #{item.duration}, #{item.teacher}, #{item.status}, #{item.viewCount},
#{item.learnCount}, #{item.orderNum}, #{item.creator}, #{item.updater},
#{item.createTime}, #{item.updateTime}, #{item.deleteTime}, #{item.deleted}
#{item.content}, #{item.duration}, #{item.teacher}, #{item.status}, 0,
0, #{item.orderNum}, #{item.creator}, #{item.createTime}, #{item.deleteTime}, #{item.deleted}
)
</foreach>
</insert>
@@ -292,4 +291,14 @@
SET view_count = view_count + 1
WHERE course_id = #{courseID} AND deleted = 0
</update>
<!-- incrementLearnCount -->
<update id="incrementLearnCount">
UPDATE tb_course
SET learn_count = learn_count + #{count}
WHERE course_id = #{courseID} AND deleted = 0
</update>
</mapper>

View File

@@ -23,6 +23,27 @@
<result column="deleted" property="deleted" jdbcType="BOOLEAN"/>
</resultMap>
<resultMap id="CourseItemResultMap" type="org.xyzh.common.vo.CourseItemVO">
<id column="id" property="id" jdbcType="VARCHAR"/>
<result column="node_id" property="nodeID" jdbcType="VARCHAR"/>
<result column="chapter_id" property="chapterID" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="node_type" property="nodeType" jdbcType="INTEGER"/>
<result column="resource_id" property="resourceID" jdbcType="VARCHAR"/>
<result column="video_url" property="videoUrl" jdbcType="VARCHAR"/>
<result column="duration" property="duration" jdbcType="INTEGER"/>
<result column="order_num" property="orderNum" jdbcType="INTEGER"/>
<result column="is_required" property="isRequired" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<!-- 学习记录相关字段 -->
<result column="progress" property="progress" jdbcType="DECIMAL"/>
<result column="is_complete" property="isComplete" jdbcType="BOOLEAN"/>
<result column="learning_duration" property="learningDuration" jdbcType="INTEGER"/>
<result column="last_learn_time" property="lastLearnTime" jdbcType="TIMESTAMP"/>
<result column="complete_time" property="completeTime" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 基础字段 -->
<sql id="Base_Column_List">
id, node_id, chapter_id, name, content, node_type, resource_id, video_url, duration, order_num, is_required,
@@ -236,4 +257,41 @@
AND deleted = 0
ORDER BY order_num ASC, create_time ASC
</select>
<!-- selectNodesProgress -->
<select id="selectNodesProgress" resultMap="CourseItemResultMap">
SELECT
tcn.id,
tcn.node_id,
tcn.chapter_id,
tcn.`name`,
tcn.content,
tcn.node_type,
tcn.resource_id,
tcn.video_url,
tcn.duration,
tcn.order_num,
tcn.is_required,
tcn.create_time,
tlr.duration as learning_duration,
tlr.progress,
tlr.is_complete,
tlr.last_learn_time,
tlr.complete_time
FROM
tb_course_node tcn
LEFT JOIN tb_learning_record tlr ON tcn.node_id = tlr.node_id
<if test="userID != null and userID != ''">
AND tlr.user_id = #{userID}
</if>
WHERE
tcn.chapter_id IN
<foreach collection="chapterIDs" item="chapterID" open="(" separator="," close=")">
#{chapterID}
</foreach>
AND tcn.deleted = 0
ORDER BY
tcn.order_num ASC,
tcn.create_time ASC
</select>
</mapper>

View File

@@ -125,11 +125,9 @@
<!-- 插入学习记录 -->
<insert id="insertLearningRecord" parameterType="org.xyzh.common.dto.study.TbLearningRecord">
INSERT INTO tb_learning_record (
id, user_id, task_id, resource_type, resource_id, course_id, chapter_id, node_id, duration, progress,
is_complete, complete_time, last_learn_time, create_time
id, user_id, task_id, resource_type, resource_id, course_id, chapter_id, node_id, create_time
) VALUES (
#{id}, #{userID}, #{taskID}, #{resourceType}, #{resourceID}, #{courseID}, #{chapterID}, #{nodeID}, #{duration}, #{progress},
#{isComplete}, #{completeTime}, #{lastLearnTime}, #{createTime}
#{id}, #{userID}, #{taskID}, #{resourceType}, #{resourceID}, #{courseID}, #{chapterID}, #{nodeID}, #{createTime}
)
</insert>
@@ -171,14 +169,11 @@
<!-- 批量插入学习记录 -->
<insert id="batchInsertLearningRecords" parameterType="java.util.List">
INSERT INTO tb_learning_record (
id, user_id, resource_type, resource_id, task_id, duration, progress,
is_complete, complete_time, last_learn_time, create_time, update_time
id, user_id, resource_type, resource_id, task_id, course_id, chapter_id, node_id, create_time
) VALUES
<foreach collection="learningRecordList" item="item" separator=",">
(
#{item.id}, #{item.userID}, #{item.resourceType}, #{item.resourceID}, #{item.taskID},
#{item.duration}, #{item.progress}, #{item.isComplete}, #{item.completeTime},
#{item.lastLearnTime}, #{item.createTime}, #{item.updateTime}
#{item.id}, #{item.userID}, #{item.resourceType}, #{item.resourceID}, #{item.taskID}, #{item.courseID}, #{item.chapterID}, #{item.nodeID}, #{item.createTime}
)
</foreach>
</insert>

View File

@@ -152,9 +152,9 @@
<!-- 插入任务用户关联 -->
<insert id="insertTaskUser" parameterType="org.xyzh.common.dto.study.TbTaskUser">
INSERT INTO tb_task_user (
id, task_id, user_id, dept_id,creator, create_time
id, task_id, user_id, dept_id,creator, status, progress, create_time
) VALUES (
#{id}, #{taskID}, #{userID}, #{deptID}, #{creator}, #{createTime}
#{id}, #{taskID}, #{userID}, #{deptID}, #{creator}, 0, 0, #{createTime}
)
</insert>
@@ -193,8 +193,8 @@
) VALUES
<foreach collection="taskUserList" item="item" separator=",">
(
#{item.id}, #{item.taskID}, #{item.userID}, #{item.deptID}, #{item.status},
#{item.progress}, #{item.completeTime}, #{item.creator}, #{item.createTime}
#{item.id}, #{item.taskID}, #{item.userID}, #{item.deptID}, 0,
0, #{item.completeTime}, #{item.creator}, #{item.createTime}
)
</foreach>
</insert>