serv\web-学习历史修改
This commit is contained in:
@@ -116,3 +116,78 @@ CREATE TABLE `tb_learning_statistics` (
|
||||
KEY `idx_date` (`stat_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='学习统计表';
|
||||
|
||||
-- 学习观看历史表(记录每次学习行为)
|
||||
DROP TABLE IF EXISTS `tb_learning_history`;
|
||||
CREATE TABLE `tb_learning_history` (
|
||||
`id` VARCHAR(50) NOT NULL COMMENT 'ID',
|
||||
`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID',
|
||||
`history_id` VARCHAR(50) DEFAULT NULL COMMENT '学习历史ID',
|
||||
|
||||
-- 学习对象
|
||||
`resource_type` INT(4) NOT NULL COMMENT '资源类型(1资源/新闻 2课程 3章节 4节点)',
|
||||
`resource_id` VARCHAR(50) DEFAULT NULL COMMENT '资源ID',
|
||||
`course_id` VARCHAR(50) DEFAULT NULL COMMENT '课程ID',
|
||||
`chapter_id` VARCHAR(50) DEFAULT NULL COMMENT '章节ID',
|
||||
`node_id` VARCHAR(50) DEFAULT NULL COMMENT '节点ID',
|
||||
`task_id` VARCHAR(50) DEFAULT NULL COMMENT '关联任务ID',
|
||||
|
||||
-- 学习时间
|
||||
`start_time` TIMESTAMP NOT NULL COMMENT '开始学习时间',
|
||||
`end_time` TIMESTAMP NULL DEFAULT NULL COMMENT '结束学习时间',
|
||||
`duration` INT(11) DEFAULT 0 COMMENT '本次学习时长(秒)',
|
||||
|
||||
-- 学习进度
|
||||
`start_progress` DECIMAL(5,2) DEFAULT 0.00 COMMENT '开始进度(0-100)',
|
||||
`end_progress` DECIMAL(5,2) DEFAULT 0.00 COMMENT '结束进度(0-100)',
|
||||
|
||||
-- 设备信息(可选)
|
||||
`device_type` VARCHAR(20) DEFAULT NULL COMMENT '设备类型(web/mobile/app)',
|
||||
`ip_address` VARCHAR(50) DEFAULT NULL COMMENT 'IP地址',
|
||||
|
||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`delete_time` TIMESTAMP NULL DEFAULT NULL COMMENT '删除时间',
|
||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_time` (`user_id`, `start_time`),
|
||||
KEY `idx_user_resource` (`user_id`, `resource_type`, `resource_id`),
|
||||
KEY `idx_course` (`course_id`),
|
||||
KEY `idx_task` (`task_id`),
|
||||
KEY `idx_history` (`history_id`),
|
||||
KEY `idx_start_time` (`start_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='学习观看历史表';
|
||||
|
||||
-- 学习统计明细表(按天按资源统计)
|
||||
DROP TABLE IF EXISTS `tb_learning_statistics_detail`;
|
||||
CREATE TABLE `tb_learning_statistics_detail` (
|
||||
`id` VARCHAR(50) NOT NULL COMMENT '统计ID',
|
||||
`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID',
|
||||
`stat_date` DATE NOT NULL COMMENT '统计日期',
|
||||
|
||||
-- 学习对象
|
||||
`resource_type` INT(4) NOT NULL COMMENT '资源类型(1资源/新闻 2课程 3章节)',
|
||||
`resource_id` VARCHAR(50) DEFAULT NULL COMMENT '资源ID',
|
||||
`course_id` VARCHAR(50) DEFAULT NULL COMMENT '课程ID',
|
||||
`chapter_id` VARCHAR(50) DEFAULT NULL COMMENT '章节ID',
|
||||
|
||||
-- 统计数据
|
||||
`total_duration` INT(11) DEFAULT 0 COMMENT '学习时长(秒)',
|
||||
`learn_count` INT(11) DEFAULT 0 COMMENT '学习次数',
|
||||
`is_complete` TINYINT(1) DEFAULT 0 COMMENT '是否完成',
|
||||
`complete_time` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
|
||||
|
||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
||||
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`delete_time` TIMESTAMP NULL DEFAULT NULL COMMENT '删除时间',
|
||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_date_resource` (`user_id`, `stat_date`, `resource_type`, `resource_id`, `course_id`, `chapter_id`),
|
||||
KEY `idx_user_date` (`user_id`, `stat_date`),
|
||||
KEY `idx_date` (`stat_date`),
|
||||
KEY `idx_resource` (`resource_type`, `resource_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='学习统计明细表';
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.xyzh.api.study.history;
|
||||
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.dto.study.TbLearningHistory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 学习历史API接口(供其他模块调用)
|
||||
* @filename LearningHistoryAPI.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public interface LearningHistoryAPI {
|
||||
|
||||
/**
|
||||
* @description 记录学习历史
|
||||
* @param learningHistory 学习历史
|
||||
* @return ResultDomain<TbLearningHistory> 记录结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<TbLearningHistory> recordLearningHistory(TbLearningHistory learningHistory);
|
||||
|
||||
/**
|
||||
* @description 批量记录学习历史
|
||||
* @param historyList 学习历史列表
|
||||
* @return ResultDomain<Boolean> 记录结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<Boolean> batchRecordLearningHistory(List<TbLearningHistory> historyList);
|
||||
|
||||
/**
|
||||
* @description 简化记录方法 - 观看新闻/资源
|
||||
* @param userId 用户ID
|
||||
* @param resourceId 资源ID
|
||||
* @param duration 学习时长(秒)
|
||||
* @return ResultDomain<TbLearningHistory> 记录结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<TbLearningHistory> recordResourceView(String userId, String resourceId, Integer duration);
|
||||
|
||||
/**
|
||||
* @description 简化记录方法 - 学习课程
|
||||
* @param userId 用户ID
|
||||
* @param courseId 课程ID
|
||||
* @param chapterId 章节ID(可选)
|
||||
* @param nodeId 节点ID(可选)
|
||||
* @param duration 学习时长(秒)
|
||||
* @return ResultDomain<TbLearningHistory> 记录结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<TbLearningHistory> recordCourseLearn(String userId, String courseId, String chapterId, String nodeId, Integer duration);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
package org.xyzh.common.dto.study;
|
||||
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 学习观看历史表
|
||||
* @filename TbLearningHistory.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public class TbLearningHistory extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @description 用户ID
|
||||
*/
|
||||
private String userID;
|
||||
|
||||
/**
|
||||
* @description 学习会话ID
|
||||
*/
|
||||
private String historyID;
|
||||
|
||||
/**
|
||||
* @description 资源类型(1资源/新闻 2课程 3章节 4节点)
|
||||
*/
|
||||
private Integer resourceType;
|
||||
|
||||
/**
|
||||
* @description 资源ID
|
||||
*/
|
||||
private String resourceID;
|
||||
|
||||
/**
|
||||
* @description 课程ID
|
||||
*/
|
||||
private String courseID;
|
||||
|
||||
/**
|
||||
* @description 章节ID
|
||||
*/
|
||||
private String chapterID;
|
||||
|
||||
/**
|
||||
* @description 节点ID
|
||||
*/
|
||||
private String nodeID;
|
||||
|
||||
/**
|
||||
* @description 关联任务ID
|
||||
*/
|
||||
private String taskID;
|
||||
|
||||
/**
|
||||
* @description 开始学习时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* @description 结束学习时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* @description 本次学习时长(秒)
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* @description 开始进度(0-100)
|
||||
*/
|
||||
private BigDecimal startProgress;
|
||||
|
||||
/**
|
||||
* @description 结束进度(0-100)
|
||||
*/
|
||||
private BigDecimal endProgress;
|
||||
|
||||
/**
|
||||
* @description 设备类型(web/mobile/app)
|
||||
*/
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* @description IP地址
|
||||
*/
|
||||
private String ipAddress;
|
||||
|
||||
/**
|
||||
* @description 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
public void setUserID(String userID) {
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
public String getHistoryID() {
|
||||
return historyID;
|
||||
}
|
||||
|
||||
public void setHistoryID(String historyID) {
|
||||
this.historyID = historyID;
|
||||
}
|
||||
|
||||
public Integer getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(Integer resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceID() {
|
||||
return resourceID;
|
||||
}
|
||||
|
||||
public void setResourceID(String resourceID) {
|
||||
this.resourceID = resourceID;
|
||||
}
|
||||
|
||||
public String getCourseID() {
|
||||
return courseID;
|
||||
}
|
||||
|
||||
public void setCourseID(String courseID) {
|
||||
this.courseID = courseID;
|
||||
}
|
||||
|
||||
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 getTaskID() {
|
||||
return taskID;
|
||||
}
|
||||
|
||||
public void setTaskID(String taskID) {
|
||||
this.taskID = taskID;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Date getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Date endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public Integer getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(Integer duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public BigDecimal getStartProgress() {
|
||||
return startProgress;
|
||||
}
|
||||
|
||||
public void setStartProgress(BigDecimal startProgress) {
|
||||
this.startProgress = startProgress;
|
||||
}
|
||||
|
||||
public BigDecimal getEndProgress() {
|
||||
return endProgress;
|
||||
}
|
||||
|
||||
public void setEndProgress(BigDecimal endProgress) {
|
||||
this.endProgress = endProgress;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public String getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public void setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TbLearningHistory{" +
|
||||
"id=" + getID() +
|
||||
", userID='" + userID + '\'' +
|
||||
", historyID='" + historyID + '\'' +
|
||||
", resourceType=" + resourceType +
|
||||
", resourceID='" + resourceID + '\'' +
|
||||
", courseID='" + courseID + '\'' +
|
||||
", chapterID='" + chapterID + '\'' +
|
||||
", nodeID='" + nodeID + '\'' +
|
||||
", taskID='" + taskID + '\'' +
|
||||
", startTime=" + startTime +
|
||||
", endTime=" + endTime +
|
||||
", duration=" + duration +
|
||||
", startProgress=" + startProgress +
|
||||
", endProgress=" + endProgress +
|
||||
", deviceType='" + deviceType + '\'' +
|
||||
", ipAddress='" + ipAddress + '\'' +
|
||||
", creator='" + creator + '\'' +
|
||||
", createTime=" + getCreateTime() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
package org.xyzh.common.dto.study;
|
||||
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 学习统计明细表
|
||||
* @filename TbLearningStatisticsDetail.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public class TbLearningStatisticsDetail extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @description 用户ID
|
||||
*/
|
||||
private String userID;
|
||||
|
||||
/**
|
||||
* @description 统计日期
|
||||
*/
|
||||
private Date statDate;
|
||||
|
||||
/**
|
||||
* @description 资源类型(1资源/新闻 2课程 3章节)
|
||||
*/
|
||||
private Integer resourceType;
|
||||
|
||||
/**
|
||||
* @description 资源ID
|
||||
*/
|
||||
private String resourceID;
|
||||
|
||||
/**
|
||||
* @description 课程ID
|
||||
*/
|
||||
private String courseID;
|
||||
|
||||
/**
|
||||
* @description 章节ID
|
||||
*/
|
||||
private String chapterID;
|
||||
|
||||
/**
|
||||
* @description 学习时长(秒)
|
||||
*/
|
||||
private Integer totalDuration;
|
||||
|
||||
/**
|
||||
* @description 学习次数
|
||||
*/
|
||||
private Integer learnCount;
|
||||
|
||||
/**
|
||||
* @description 是否完成
|
||||
*/
|
||||
private Boolean isComplete;
|
||||
|
||||
/**
|
||||
* @description 完成时间
|
||||
*/
|
||||
private Date completeTime;
|
||||
|
||||
/**
|
||||
* @description 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* @description 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
public void setUserID(String userID) {
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
public Date getStatDate() {
|
||||
return statDate;
|
||||
}
|
||||
|
||||
public void setStatDate(Date statDate) {
|
||||
this.statDate = statDate;
|
||||
}
|
||||
|
||||
public Integer getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(Integer resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceID() {
|
||||
return resourceID;
|
||||
}
|
||||
|
||||
public void setResourceID(String resourceID) {
|
||||
this.resourceID = resourceID;
|
||||
}
|
||||
|
||||
public String getCourseID() {
|
||||
return courseID;
|
||||
}
|
||||
|
||||
public void setCourseID(String courseID) {
|
||||
this.courseID = courseID;
|
||||
}
|
||||
|
||||
public String getChapterID() {
|
||||
return chapterID;
|
||||
}
|
||||
|
||||
public void setChapterID(String chapterID) {
|
||||
this.chapterID = chapterID;
|
||||
}
|
||||
|
||||
public Integer getTotalDuration() {
|
||||
return totalDuration;
|
||||
}
|
||||
|
||||
public void setTotalDuration(Integer totalDuration) {
|
||||
this.totalDuration = totalDuration;
|
||||
}
|
||||
|
||||
public Integer getLearnCount() {
|
||||
return learnCount;
|
||||
}
|
||||
|
||||
public void setLearnCount(Integer learnCount) {
|
||||
this.learnCount = learnCount;
|
||||
}
|
||||
|
||||
public Boolean getIsComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
public void setIsComplete(Boolean isComplete) {
|
||||
this.isComplete = isComplete;
|
||||
}
|
||||
|
||||
public Date getCompleteTime() {
|
||||
return completeTime;
|
||||
}
|
||||
|
||||
public void setCompleteTime(Date completeTime) {
|
||||
this.completeTime = completeTime;
|
||||
}
|
||||
|
||||
public String getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public void setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public String getUpdater() {
|
||||
return updater;
|
||||
}
|
||||
|
||||
public void setUpdater(String updater) {
|
||||
this.updater = updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TbLearningStatisticsDetail{" +
|
||||
"id=" + getID() +
|
||||
", userID='" + userID + '\'' +
|
||||
", statDate=" + statDate +
|
||||
", resourceType=" + resourceType +
|
||||
", resourceID='" + resourceID + '\'' +
|
||||
", courseID='" + courseID + '\'' +
|
||||
", chapterID='" + chapterID + '\'' +
|
||||
", totalDuration=" + totalDuration +
|
||||
", learnCount=" + learnCount +
|
||||
", isComplete=" + isComplete +
|
||||
", completeTime=" + completeTime +
|
||||
", creator='" + creator + '\'' +
|
||||
", updater='" + updater + '\'' +
|
||||
", createTime=" + getCreateTime() +
|
||||
", updateTime=" + getUpdateTime() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
package org.xyzh.common.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 学习历史响应VO
|
||||
* @filename LearningHistoryVO.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public class LearningHistoryVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @description 历史记录ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* @description 用户ID
|
||||
*/
|
||||
private String userID;
|
||||
|
||||
/**
|
||||
* @description 用户名称(关联查询)
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* @description 学习会话ID
|
||||
*/
|
||||
private String sessionID;
|
||||
|
||||
/**
|
||||
* @description 资源类型(1资源/新闻 2课程 3章节 4节点)
|
||||
*/
|
||||
private Integer resourceType;
|
||||
|
||||
/**
|
||||
* @description 资源类型名称
|
||||
*/
|
||||
private String resourceTypeName;
|
||||
|
||||
/**
|
||||
* @description 资源ID
|
||||
*/
|
||||
private String resourceID;
|
||||
|
||||
/**
|
||||
* @description 资源标题(关联查询)
|
||||
*/
|
||||
private String resourceTitle;
|
||||
|
||||
/**
|
||||
* @description 课程ID
|
||||
*/
|
||||
private String courseID;
|
||||
|
||||
/**
|
||||
* @description 课程名称(关联查询)
|
||||
*/
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* @description 章节ID
|
||||
*/
|
||||
private String chapterID;
|
||||
|
||||
/**
|
||||
* @description 章节名称(关联查询)
|
||||
*/
|
||||
private String chapterName;
|
||||
|
||||
/**
|
||||
* @description 节点ID
|
||||
*/
|
||||
private String nodeID;
|
||||
|
||||
/**
|
||||
* @description 节点名称(关联查询)
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* @description 关联任务ID
|
||||
*/
|
||||
private String taskID;
|
||||
|
||||
/**
|
||||
* @description 任务名称(关联查询)
|
||||
*/
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* @description 开始学习时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* @description 结束学习时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* @description 本次学习时长(秒)
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* @description 学习时长(格式化后,如:1小时20分钟)
|
||||
*/
|
||||
private String durationFormatted;
|
||||
|
||||
/**
|
||||
* @description 开始进度(0-100)
|
||||
*/
|
||||
private BigDecimal startProgress;
|
||||
|
||||
/**
|
||||
* @description 结束进度(0-100)
|
||||
*/
|
||||
private BigDecimal endProgress;
|
||||
|
||||
/**
|
||||
* @description 设备类型
|
||||
*/
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* @description 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
// Getters and Setters
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
public void setUserID(String userID) {
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getSessionID() {
|
||||
return sessionID;
|
||||
}
|
||||
|
||||
public void setSessionID(String sessionID) {
|
||||
this.sessionID = sessionID;
|
||||
}
|
||||
|
||||
public Integer getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(Integer resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceTypeName() {
|
||||
return resourceTypeName;
|
||||
}
|
||||
|
||||
public void setResourceTypeName(String resourceTypeName) {
|
||||
this.resourceTypeName = resourceTypeName;
|
||||
}
|
||||
|
||||
public String getResourceID() {
|
||||
return resourceID;
|
||||
}
|
||||
|
||||
public void setResourceID(String resourceID) {
|
||||
this.resourceID = resourceID;
|
||||
}
|
||||
|
||||
public String getResourceTitle() {
|
||||
return resourceTitle;
|
||||
}
|
||||
|
||||
public void setResourceTitle(String resourceTitle) {
|
||||
this.resourceTitle = resourceTitle;
|
||||
}
|
||||
|
||||
public String getCourseID() {
|
||||
return courseID;
|
||||
}
|
||||
|
||||
public void setCourseID(String courseID) {
|
||||
this.courseID = courseID;
|
||||
}
|
||||
|
||||
public String getCourseName() {
|
||||
return courseName;
|
||||
}
|
||||
|
||||
public void setCourseName(String courseName) {
|
||||
this.courseName = courseName;
|
||||
}
|
||||
|
||||
public String getChapterID() {
|
||||
return chapterID;
|
||||
}
|
||||
|
||||
public void setChapterID(String chapterID) {
|
||||
this.chapterID = chapterID;
|
||||
}
|
||||
|
||||
public String getChapterName() {
|
||||
return chapterName;
|
||||
}
|
||||
|
||||
public void setChapterName(String chapterName) {
|
||||
this.chapterName = chapterName;
|
||||
}
|
||||
|
||||
public String getNodeID() {
|
||||
return nodeID;
|
||||
}
|
||||
|
||||
public void setNodeID(String nodeID) {
|
||||
this.nodeID = nodeID;
|
||||
}
|
||||
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
public void setNodeName(String nodeName) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
|
||||
public String getTaskID() {
|
||||
return taskID;
|
||||
}
|
||||
|
||||
public void setTaskID(String taskID) {
|
||||
this.taskID = taskID;
|
||||
}
|
||||
|
||||
public String getTaskName() {
|
||||
return taskName;
|
||||
}
|
||||
|
||||
public void setTaskName(String taskName) {
|
||||
this.taskName = taskName;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Date getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Date endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public Integer getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(Integer duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getDurationFormatted() {
|
||||
return durationFormatted;
|
||||
}
|
||||
|
||||
public void setDurationFormatted(String durationFormatted) {
|
||||
this.durationFormatted = durationFormatted;
|
||||
}
|
||||
|
||||
public BigDecimal getStartProgress() {
|
||||
return startProgress;
|
||||
}
|
||||
|
||||
public void setStartProgress(BigDecimal startProgress) {
|
||||
this.startProgress = startProgress;
|
||||
}
|
||||
|
||||
public BigDecimal getEndProgress() {
|
||||
return endProgress;
|
||||
}
|
||||
|
||||
public void setEndProgress(BigDecimal endProgress) {
|
||||
this.endProgress = endProgress;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LearningHistoryVO{" +
|
||||
"id='" + id + '\'' +
|
||||
", userID='" + userID + '\'' +
|
||||
", userName='" + userName + '\'' +
|
||||
", resourceType=" + resourceType +
|
||||
", resourceTypeName='" + resourceTypeName + '\'' +
|
||||
", resourceTitle='" + resourceTitle + '\'' +
|
||||
", duration=" + duration +
|
||||
", durationFormatted='" + durationFormatted + '\'' +
|
||||
", startTime=" + startTime +
|
||||
", endTime=" + endTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
package org.xyzh.common.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 学习统计明细VO
|
||||
* @filename LearningStatisticsDetailVO.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public class LearningStatisticsDetailVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @description 统计日期
|
||||
*/
|
||||
private Date statDate;
|
||||
|
||||
/**
|
||||
* @description 资源类型(1资源/新闻 2课程 3章节)
|
||||
*/
|
||||
private Integer resourceType;
|
||||
|
||||
/**
|
||||
* @description 资源类型名称
|
||||
*/
|
||||
private String resourceTypeName;
|
||||
|
||||
/**
|
||||
* @description 资源ID
|
||||
*/
|
||||
private String resourceID;
|
||||
|
||||
/**
|
||||
* @description 资源标题
|
||||
*/
|
||||
private String resourceTitle;
|
||||
|
||||
/**
|
||||
* @description 课程ID
|
||||
*/
|
||||
private String courseID;
|
||||
|
||||
/**
|
||||
* @description 课程名称
|
||||
*/
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* @description 章节ID
|
||||
*/
|
||||
private String chapterID;
|
||||
|
||||
/**
|
||||
* @description 章节名称
|
||||
*/
|
||||
private String chapterName;
|
||||
|
||||
/**
|
||||
* @description 学习时长(秒)
|
||||
*/
|
||||
private Integer totalDuration;
|
||||
|
||||
/**
|
||||
* @description 学习时长(格式化)
|
||||
*/
|
||||
private String totalDurationFormatted;
|
||||
|
||||
/**
|
||||
* @description 学习次数
|
||||
*/
|
||||
private Integer learnCount;
|
||||
|
||||
/**
|
||||
* @description 是否完成
|
||||
*/
|
||||
private Boolean isComplete;
|
||||
|
||||
/**
|
||||
* @description 完成时间
|
||||
*/
|
||||
private Date completeTime;
|
||||
|
||||
public Date getStatDate() {
|
||||
return statDate;
|
||||
}
|
||||
|
||||
public void setStatDate(Date statDate) {
|
||||
this.statDate = statDate;
|
||||
}
|
||||
|
||||
public Integer getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(Integer resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceTypeName() {
|
||||
return resourceTypeName;
|
||||
}
|
||||
|
||||
public void setResourceTypeName(String resourceTypeName) {
|
||||
this.resourceTypeName = resourceTypeName;
|
||||
}
|
||||
|
||||
public String getResourceID() {
|
||||
return resourceID;
|
||||
}
|
||||
|
||||
public void setResourceID(String resourceID) {
|
||||
this.resourceID = resourceID;
|
||||
}
|
||||
|
||||
public String getResourceTitle() {
|
||||
return resourceTitle;
|
||||
}
|
||||
|
||||
public void setResourceTitle(String resourceTitle) {
|
||||
this.resourceTitle = resourceTitle;
|
||||
}
|
||||
|
||||
public String getCourseID() {
|
||||
return courseID;
|
||||
}
|
||||
|
||||
public void setCourseID(String courseID) {
|
||||
this.courseID = courseID;
|
||||
}
|
||||
|
||||
public String getCourseName() {
|
||||
return courseName;
|
||||
}
|
||||
|
||||
public void setCourseName(String courseName) {
|
||||
this.courseName = courseName;
|
||||
}
|
||||
|
||||
public String getChapterID() {
|
||||
return chapterID;
|
||||
}
|
||||
|
||||
public void setChapterID(String chapterID) {
|
||||
this.chapterID = chapterID;
|
||||
}
|
||||
|
||||
public String getChapterName() {
|
||||
return chapterName;
|
||||
}
|
||||
|
||||
public void setChapterName(String chapterName) {
|
||||
this.chapterName = chapterName;
|
||||
}
|
||||
|
||||
public Integer getTotalDuration() {
|
||||
return totalDuration;
|
||||
}
|
||||
|
||||
public void setTotalDuration(Integer totalDuration) {
|
||||
this.totalDuration = totalDuration;
|
||||
}
|
||||
|
||||
public String getTotalDurationFormatted() {
|
||||
return totalDurationFormatted;
|
||||
}
|
||||
|
||||
public void setTotalDurationFormatted(String totalDurationFormatted) {
|
||||
this.totalDurationFormatted = totalDurationFormatted;
|
||||
}
|
||||
|
||||
public Integer getLearnCount() {
|
||||
return learnCount;
|
||||
}
|
||||
|
||||
public void setLearnCount(Integer learnCount) {
|
||||
this.learnCount = learnCount;
|
||||
}
|
||||
|
||||
public Boolean getIsComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
public void setIsComplete(Boolean isComplete) {
|
||||
this.isComplete = isComplete;
|
||||
}
|
||||
|
||||
public Date getCompleteTime() {
|
||||
return completeTime;
|
||||
}
|
||||
|
||||
public void setCompleteTime(Date completeTime) {
|
||||
this.completeTime = completeTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LearningStatisticsDetailVO{" +
|
||||
"statDate=" + statDate +
|
||||
", resourceType=" + resourceType +
|
||||
", resourceTypeName='" + resourceTypeName + '\'' +
|
||||
", resourceTitle='" + resourceTitle + '\'' +
|
||||
", totalDuration=" + totalDuration +
|
||||
", totalDurationFormatted='" + totalDurationFormatted + '\'' +
|
||||
", learnCount=" + learnCount +
|
||||
", isComplete=" + isComplete +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package org.xyzh.common.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 学习统计响应VO
|
||||
* @filename LearningStatisticsVO.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public class LearningStatisticsVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @description 用户ID
|
||||
*/
|
||||
private String userID;
|
||||
|
||||
/**
|
||||
* @description 统计周期(day/week/month)
|
||||
*/
|
||||
private String period;
|
||||
|
||||
/**
|
||||
* @description 总学习时长(秒)
|
||||
*/
|
||||
private Integer totalDuration;
|
||||
|
||||
/**
|
||||
* @description 总学习时长(格式化)
|
||||
*/
|
||||
private String totalDurationFormatted;
|
||||
|
||||
/**
|
||||
* @description 学习天数
|
||||
*/
|
||||
private Integer learnDays;
|
||||
|
||||
/**
|
||||
* @description 学习资源数量
|
||||
*/
|
||||
private Integer resourceCount;
|
||||
|
||||
/**
|
||||
* @description 学习课程数量
|
||||
*/
|
||||
private Integer courseCount;
|
||||
|
||||
/**
|
||||
* @description 学习次数
|
||||
*/
|
||||
private Integer learnCount;
|
||||
|
||||
/**
|
||||
* @description 完成数量
|
||||
*/
|
||||
private Integer completeCount;
|
||||
|
||||
/**
|
||||
* @description 平均每天学习时长(秒)
|
||||
*/
|
||||
private Integer avgDailyDuration;
|
||||
|
||||
/**
|
||||
* @description 学习明细列表
|
||||
*/
|
||||
private List<LearningStatisticsDetailVO> details;
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
public void setUserID(String userID) {
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
public String getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public void setPeriod(String period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public Integer getTotalDuration() {
|
||||
return totalDuration;
|
||||
}
|
||||
|
||||
public void setTotalDuration(Integer totalDuration) {
|
||||
this.totalDuration = totalDuration;
|
||||
}
|
||||
|
||||
public String getTotalDurationFormatted() {
|
||||
return totalDurationFormatted;
|
||||
}
|
||||
|
||||
public void setTotalDurationFormatted(String totalDurationFormatted) {
|
||||
this.totalDurationFormatted = totalDurationFormatted;
|
||||
}
|
||||
|
||||
public Integer getLearnDays() {
|
||||
return learnDays;
|
||||
}
|
||||
|
||||
public void setLearnDays(Integer learnDays) {
|
||||
this.learnDays = learnDays;
|
||||
}
|
||||
|
||||
public Integer getResourceCount() {
|
||||
return resourceCount;
|
||||
}
|
||||
|
||||
public void setResourceCount(Integer resourceCount) {
|
||||
this.resourceCount = resourceCount;
|
||||
}
|
||||
|
||||
public Integer getCourseCount() {
|
||||
return courseCount;
|
||||
}
|
||||
|
||||
public void setCourseCount(Integer courseCount) {
|
||||
this.courseCount = courseCount;
|
||||
}
|
||||
|
||||
public Integer getLearnCount() {
|
||||
return learnCount;
|
||||
}
|
||||
|
||||
public void setLearnCount(Integer learnCount) {
|
||||
this.learnCount = learnCount;
|
||||
}
|
||||
|
||||
public Integer getCompleteCount() {
|
||||
return completeCount;
|
||||
}
|
||||
|
||||
public void setCompleteCount(Integer completeCount) {
|
||||
this.completeCount = completeCount;
|
||||
}
|
||||
|
||||
public Integer getAvgDailyDuration() {
|
||||
return avgDailyDuration;
|
||||
}
|
||||
|
||||
public void setAvgDailyDuration(Integer avgDailyDuration) {
|
||||
this.avgDailyDuration = avgDailyDuration;
|
||||
}
|
||||
|
||||
public List<LearningStatisticsDetailVO> getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(List<LearningStatisticsDetailVO> details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LearningStatisticsVO{" +
|
||||
"userID='" + userID + '\'' +
|
||||
", period='" + period + '\'' +
|
||||
", totalDuration=" + totalDuration +
|
||||
", totalDurationFormatted='" + totalDurationFormatted + '\'' +
|
||||
", learnDays=" + learnDays +
|
||||
", resourceCount=" + resourceCount +
|
||||
", courseCount=" + courseCount +
|
||||
", learnCount=" + learnCount +
|
||||
", completeCount=" + completeCount +
|
||||
", avgDailyDuration=" + avgDailyDuration +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/task/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> getTaskById(@PathVariable String taskId) {
|
||||
public ResultDomain<TbCrontabTask> getTaskById(@PathVariable(value = "taskId") String taskId) {
|
||||
return crontabService.getTaskById(taskId);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/start/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> startTask(@PathVariable String taskId) {
|
||||
public ResultDomain<TbCrontabTask> startTask(@PathVariable(value = "taskId") String taskId) {
|
||||
return crontabService.startTask(taskId);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/pause/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> pauseTask(@PathVariable String taskId) {
|
||||
public ResultDomain<TbCrontabTask> pauseTask(@PathVariable(value = "taskId") String taskId) {
|
||||
return crontabService.pauseTask(taskId);
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/execute/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> executeTaskOnce(@PathVariable String taskId) {
|
||||
public ResultDomain<TbCrontabTask> executeTaskOnce(@PathVariable(value = "taskId") String taskId) {
|
||||
return crontabService.executeTaskOnce(taskId);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/log/task/{taskId}")
|
||||
public ResultDomain<TbCrontabLog> getLogsByTaskId(@PathVariable String taskId) {
|
||||
public ResultDomain<TbCrontabLog> getLogsByTaskId(@PathVariable(value = "taskId") String taskId) {
|
||||
return crontabService.getLogsByTaskId(taskId);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/log/{logId}")
|
||||
public ResultDomain<TbCrontabLog> getLogById(@PathVariable String logId) {
|
||||
public ResultDomain<TbCrontabLog> getLogById(@PathVariable(value = "logId") String logId) {
|
||||
return crontabService.getLogById(logId);
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ public class CrontabController {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@DeleteMapping("/log/clean/{days}")
|
||||
public ResultDomain<Integer> cleanLogs(@PathVariable Integer days) {
|
||||
public ResultDomain<Integer> cleanLogs(@PathVariable(value = "days") Integer days) {
|
||||
return crontabService.cleanLogs(days);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,5 +100,14 @@ public interface CrontabTaskMapper extends BaseMapper<TbCrontabTask> {
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
TbCrontabTask selectTaskByBeanAndMethod(@Param("beanName") String beanName, @Param("methodName") String methodName);
|
||||
|
||||
/**
|
||||
* @description 查询任务总数
|
||||
* @param filter 过滤条件
|
||||
* @return int 任务总数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int countSelectTask(@Param("filter") TbCrontabTask filter);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.xyzh.api.crontab.CrontabService;
|
||||
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.crontab.TbCrontabTask;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabLog;
|
||||
@@ -215,7 +216,14 @@ public class CrontabServiceImpl implements CrontabService {
|
||||
}
|
||||
|
||||
List<TbCrontabTask> list = taskMapper.selectTaskPage(filter, pageParam);
|
||||
resultDomain.success("查询成功", list);
|
||||
int total = taskMapper.countSelectTask(filter);
|
||||
|
||||
PageDomain<TbCrontabTask> pageDomain = new PageDomain<>();
|
||||
pageDomain.setDataList(list);
|
||||
pageParam.setTotalElements(total);
|
||||
pageParam.setTotalPages((int) Math.ceil((double) total / pageParam.getPageSize()));
|
||||
pageDomain.setPageParam(pageParam);
|
||||
resultDomain.success("查询成功", pageDomain);
|
||||
} catch (Exception e) {
|
||||
logger.error("分页查询定时任务异常: ", e);
|
||||
resultDomain.fail("分页查询定时任务异常: " + e.getMessage());
|
||||
|
||||
@@ -33,6 +33,33 @@
|
||||
|
||||
<!-- 查询条件 -->
|
||||
<sql id="Base_Where_Clause">
|
||||
<where>
|
||||
deleted = 0
|
||||
<if test="taskId != null and taskId != ''">
|
||||
AND task_id = #{taskId}
|
||||
</if>
|
||||
<if test="taskName != null and taskName != ''">
|
||||
AND task_name LIKE CONCAT('%', #{taskName}, '%')
|
||||
</if>
|
||||
<if test="taskGroup != null and taskGroup != ''">
|
||||
AND task_group = #{taskGroup}
|
||||
</if>
|
||||
<if test="beanName != null and beanName != ''">
|
||||
AND bean_name = #{beanName}
|
||||
</if>
|
||||
<if test="methodName != null and methodName != ''">
|
||||
AND method_name = #{methodName}
|
||||
</if>
|
||||
<if test="status != null">
|
||||
AND status = #{status}
|
||||
</if>
|
||||
<if test="deleted != null">
|
||||
AND deleted = #{deleted}
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<sql id="Filter_Where_Clause">
|
||||
<where>
|
||||
<if test="filter != null">
|
||||
<if test="filter.ID != null and filter.ID != ''">
|
||||
@@ -144,7 +171,7 @@
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
<include refid="Base_Where_Clause" />
|
||||
<include refid="Filter_Where_Clause" />
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
@@ -153,7 +180,7 @@
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
<include refid="Base_Where_Clause" />
|
||||
<include refid="Filter_Where_Clause" />
|
||||
ORDER BY create_time DESC
|
||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
||||
</select>
|
||||
@@ -185,4 +212,11 @@
|
||||
AND deleted = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- countSelectTask -->
|
||||
|
||||
<select id="countSelectTask">
|
||||
SELECT COUNT(1) FROM tb_crontab_task
|
||||
<include refid="Filter_Where_Clause" />
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package org.xyzh.study.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageDomain;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.study.TbLearningHistory;
|
||||
import org.xyzh.common.vo.LearningHistoryVO;
|
||||
import org.xyzh.common.vo.LearningStatisticsVO;
|
||||
import org.xyzh.study.service.SCLearningHistoryService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 学习历史控制器
|
||||
* @filename LearningHistoryController.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/study/history")
|
||||
public class LearningHistoryController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LearningHistoryController.class);
|
||||
|
||||
@Autowired
|
||||
private SCLearningHistoryService learningHistoryService;
|
||||
|
||||
/**
|
||||
* 记录学习历史
|
||||
* POST /study/history/record
|
||||
*
|
||||
* @param learningHistory 学习历史
|
||||
* @return ResultDomain<TbLearningHistory> 记录结果
|
||||
*/
|
||||
@PostMapping("/record")
|
||||
public ResultDomain<TbLearningHistory> recordLearningHistory(@RequestBody TbLearningHistory learningHistory) {
|
||||
logger.info("记录学习历史,资源类型: {}, 资源ID: {}", learningHistory.getResourceType(), learningHistory.getResourceID());
|
||||
return learningHistoryService.recordLearningHistory(learningHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量记录学习历史
|
||||
* POST /study/history/batch-record
|
||||
*
|
||||
* @param historyList 学习历史列表
|
||||
* @return ResultDomain<Boolean> 记录结果
|
||||
*/
|
||||
@PostMapping("/batch-record")
|
||||
public ResultDomain<Boolean> batchRecordLearningHistory(@RequestBody List<TbLearningHistory> historyList) {
|
||||
logger.info("批量记录学习历史,数量: {}", historyList != null ? historyList.size() : 0);
|
||||
return learningHistoryService.batchRecordLearningHistory(historyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学习历史列表
|
||||
* POST /study/history/list
|
||||
*
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<List<LearningHistoryVO>> 学习历史列表
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public ResultDomain<List<LearningHistoryVO>> getLearningHistories(@RequestBody TbLearningHistory filter) {
|
||||
logger.info("查询学习历史列表,用户ID: {}", filter != null ? filter.getUserID() : null);
|
||||
return learningHistoryService.getLearningHistories(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询学习历史
|
||||
* POST /study/history/page
|
||||
*
|
||||
* @param pageRequest 分页查询请求
|
||||
* @return ResultDomain<PageDomain<LearningHistoryVO>> 分页结果
|
||||
*/
|
||||
@PostMapping("/page")
|
||||
public ResultDomain<PageDomain<LearningHistoryVO>> getLearningHistoriesPage(@RequestBody PageRequest<TbLearningHistory> pageRequest) {
|
||||
logger.info("分页查询学习历史,页码: {}, 每页数量: {}",
|
||||
pageRequest.getPageParam() != null ? pageRequest.getPageParam().getPageNumber() : null,
|
||||
pageRequest.getPageParam() != null ? pageRequest.getPageParam().getPageSize() : null);
|
||||
return learningHistoryService.getLearningHistoriesPage(pageRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询学习历史
|
||||
* GET /study/history/{id}
|
||||
*
|
||||
* @param id 历史记录ID
|
||||
* @return ResultDomain<TbLearningHistory> 学习历史
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResultDomain<TbLearningHistory> getLearningHistoryById(@PathVariable String id) {
|
||||
logger.info("查询学习历史,ID: {}", id);
|
||||
return learningHistoryService.getLearningHistoryById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的学习历史
|
||||
* POST /study/history/my-histories
|
||||
*
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<List<LearningHistoryVO>> 学习历史列表
|
||||
*/
|
||||
@PostMapping("/my-histories")
|
||||
public ResultDomain<List<LearningHistoryVO>> getCurrentUserLearningHistories(@RequestBody(required = false) TbLearningHistory filter) {
|
||||
logger.info("查询当前用户学习历史");
|
||||
return learningHistoryService.getCurrentUserLearningHistories(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户最近的学习历史
|
||||
* GET /study/history/recent
|
||||
*
|
||||
* @param limit 限制数量(可选,默认10)
|
||||
* @return ResultDomain<List<LearningHistoryVO>> 学习历史列表
|
||||
*/
|
||||
@GetMapping("/recent")
|
||||
public ResultDomain<List<LearningHistoryVO>> getRecentLearningHistories(@RequestParam(required = false, defaultValue = "10") Integer limit) {
|
||||
logger.info("查询最近学习历史,限制数量: {}", limit);
|
||||
// 从当前登录用户获取
|
||||
return learningHistoryService.getRecentLearningHistories(null, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户学习统计(按时间范围)
|
||||
* GET /study/history/statistics
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param startTime 开始时间(时间戳,毫秒)
|
||||
* @param endTime 结束时间(时间戳,毫秒)
|
||||
* @return ResultDomain<LearningStatisticsVO> 学习统计
|
||||
*/
|
||||
@GetMapping("/statistics")
|
||||
public ResultDomain<LearningStatisticsVO> getUserLearningStatistics(
|
||||
@RequestParam String userId,
|
||||
@RequestParam Long startTime,
|
||||
@RequestParam Long endTime) {
|
||||
logger.info("查询学习统计,用户ID: {}, 开始时间: {}, 结束时间: {}", userId, startTime, endTime);
|
||||
return learningHistoryService.getUserLearningStatistics(
|
||||
userId,
|
||||
new Date(startTime),
|
||||
new Date(endTime)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户学习统计(按周期)
|
||||
* GET /study/history/statistics/{userId}/{periodType}
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param periodType 周期类型(day/week/month)
|
||||
* @return ResultDomain<LearningStatisticsVO> 学习统计
|
||||
*/
|
||||
@GetMapping("/statistics/{userId}/{periodType}")
|
||||
public ResultDomain<LearningStatisticsVO> getUserLearningStatisticsByPeriod(
|
||||
@PathVariable String userId,
|
||||
@PathVariable String periodType) {
|
||||
logger.info("查询学习统计,用户ID: {}, 周期类型: {}", userId, periodType);
|
||||
return learningHistoryService.getUserLearningStatisticsByPeriod(userId, periodType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的学习统计
|
||||
* GET /study/history/my-statistics/{periodType}
|
||||
*
|
||||
* @param periodType 周期类型(day/week/month)
|
||||
* @return ResultDomain<LearningStatisticsVO> 学习统计
|
||||
*/
|
||||
@GetMapping("/my-statistics/{periodType}")
|
||||
public ResultDomain<LearningStatisticsVO> getCurrentUserLearningStatistics(@PathVariable String periodType) {
|
||||
logger.info("查询当前用户学习统计,周期类型: {}", periodType);
|
||||
return learningHistoryService.getCurrentUserLearningStatistics(periodType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除学习历史
|
||||
* DELETE /study/history/{id}
|
||||
*
|
||||
* @param id 历史记录ID
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResultDomain<Boolean> deleteLearningHistory(@PathVariable String id) {
|
||||
logger.info("删除学习历史,ID: {}", id);
|
||||
return learningHistoryService.deleteLearningHistory(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除学习历史
|
||||
* DELETE /study/history/batch
|
||||
*
|
||||
* @param ids 历史记录ID列表
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
*/
|
||||
@DeleteMapping("/batch")
|
||||
public ResultDomain<Boolean> batchDeleteLearningHistories(@RequestBody List<String> ids) {
|
||||
logger.info("批量删除学习历史,数量: {}", ids != null ? ids.size() : 0);
|
||||
return learningHistoryService.batchDeleteLearningHistories(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 健康检查
|
||||
* GET /study/history/health
|
||||
*
|
||||
* @return ResultDomain<String> 健康状态
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResultDomain<String> health() {
|
||||
ResultDomain<String> resultDomain = new ResultDomain<>();
|
||||
resultDomain.success("学习历史服务运行正常", "OK");
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
package org.xyzh.study.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
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.TbLearningHistory;
|
||||
import org.xyzh.common.vo.LearningHistoryVO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description 学习观看历史数据访问层
|
||||
* @filename LearningHistoryMapper.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
@Mapper
|
||||
public interface LearningHistoryMapper extends BaseMapper<TbLearningHistory> {
|
||||
|
||||
/**
|
||||
* @description 插入学习历史记录
|
||||
* @param learningHistory 学习历史
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int insertLearningHistory(TbLearningHistory learningHistory);
|
||||
|
||||
/**
|
||||
* @description 更新学习历史记录
|
||||
* @param learningHistory 学习历史
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int updateLearningHistory(TbLearningHistory learningHistory);
|
||||
|
||||
/**
|
||||
* @description 批量插入学习历史记录
|
||||
* @param historyList 学习历史列表
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int batchInsertLearningHistories(@Param("historyList") List<TbLearningHistory> historyList);
|
||||
|
||||
/**
|
||||
* @description 根据ID查询学习历史
|
||||
* @param id 历史记录ID
|
||||
* @return TbLearningHistory 学习历史
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
TbLearningHistory selectById(@Param("id") String id);
|
||||
|
||||
/**
|
||||
* @description 根据用户ID查询学习历史列表
|
||||
* @param userId 用户ID
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectByUserId(@Param("userId") String userId);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询学习历史列表
|
||||
* @param filter 过滤条件
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectLearningHistories(TbLearningHistory filter);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询学习历史VO列表(带关联信息)
|
||||
* @param filter 过滤条件
|
||||
* @return List<LearningHistoryVO> 学习历史VO列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<LearningHistoryVO> selectLearningHistoriesWithDetails(TbLearningHistory filter);
|
||||
|
||||
/**
|
||||
* @description 分页查询学习历史
|
||||
* @param filter 过滤条件
|
||||
* @param pageParam 分页参数
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectLearningHistoriesPage(@Param("filter") TbLearningHistory filter, @Param("pageParam") PageParam pageParam);
|
||||
|
||||
/**
|
||||
* @description 统计学习历史总数
|
||||
* @param filter 过滤条件
|
||||
* @return long 总数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
long countLearningHistories(@Param("filter") TbLearningHistory filter);
|
||||
|
||||
/**
|
||||
* @description 根据时间段查询学习历史
|
||||
* @param userId 用户ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectByUserIdAndTimeRange(@Param("userId") String userId,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* @description 根据时间段和资源类型查询学习历史
|
||||
* @param userId 用户ID
|
||||
* @param resourceType 资源类型
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectByUserIdAndResourceTypeAndTimeRange(
|
||||
@Param("userId") String userId,
|
||||
@Param("resourceType") Integer resourceType,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* @description 统计用户某时间段的学习时长
|
||||
* @param userId 用户ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return Map<String, Object> 统计结果(totalDuration, learnCount等)
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
Map<String, Object> selectLearningStatisticsByTimeRange(
|
||||
@Param("userId") String userId,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* @description 统计用户某时间段各资源类型的学习时长
|
||||
* @param userId 用户ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return List<Map<String, Object>> 统计结果列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<Map<String, Object>> selectLearningStatisticsByResourceType(
|
||||
@Param("userId") String userId,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* @description 获取用户学习的资源列表(按时间段)
|
||||
* @param userId 用户ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return List<Map<String, Object>> 资源列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<Map<String, Object>> selectLearnedResourcesByTimeRange(
|
||||
@Param("userId") String userId,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* @description 删除学习历史(软删除)
|
||||
* @param id 历史记录ID
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int deleteLearningHistory(@Param("id") String id);
|
||||
|
||||
/**
|
||||
* @description 批量删除学习历史(软删除)
|
||||
* @param ids 历史记录ID列表
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int batchDeleteLearningHistories(@Param("ids") List<String> ids);
|
||||
|
||||
/**
|
||||
* @description 根据会话ID查询学习历史
|
||||
* @param sessionId 会话ID
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectBySessionId(@Param("sessionId") String sessionId);
|
||||
|
||||
/**
|
||||
* @description 获取用户最近的学习历史
|
||||
* @param userId 用户ID
|
||||
* @param limit 限制数量
|
||||
* @return List<TbLearningHistory> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningHistory> selectRecentByUserId(@Param("userId") String userId, @Param("limit") Integer limit);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package org.xyzh.study.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.xyzh.common.dto.study.TbLearningStatisticsDetail;
|
||||
import org.xyzh.common.vo.LearningStatisticsDetailVO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 学习统计明细数据访问层
|
||||
* @filename LearningStatisticsDetailMapper.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
@Mapper
|
||||
public interface LearningStatisticsDetailMapper extends BaseMapper<TbLearningStatisticsDetail> {
|
||||
|
||||
/**
|
||||
* @description 插入统计明细
|
||||
* @param detail 统计明细
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int insertStatisticsDetail(TbLearningStatisticsDetail detail);
|
||||
|
||||
/**
|
||||
* @description 更新统计明细
|
||||
* @param detail 统计明细
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int updateStatisticsDetail(TbLearningStatisticsDetail detail);
|
||||
|
||||
/**
|
||||
* @description 插入或更新统计明细(ON DUPLICATE KEY UPDATE)
|
||||
* @param detail 统计明细
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int insertOrUpdateStatisticsDetail(TbLearningStatisticsDetail detail);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询统计明细
|
||||
* @param filter 过滤条件
|
||||
* @return List<TbLearningStatisticsDetail> 统计明细列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningStatisticsDetail> selectStatisticsDetails(TbLearningStatisticsDetail filter);
|
||||
|
||||
/**
|
||||
* @description 根据用户ID和日期查询统计明细
|
||||
* @param userId 用户ID
|
||||
* @param statDate 统计日期
|
||||
* @return List<TbLearningStatisticsDetail> 统计明细列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningStatisticsDetail> selectByUserIdAndDate(
|
||||
@Param("userId") String userId,
|
||||
@Param("statDate") Date statDate);
|
||||
|
||||
/**
|
||||
* @description 根据用户ID和日期范围查询统计明细
|
||||
* @param userId 用户ID
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return List<TbLearningStatisticsDetail> 统计明细列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningStatisticsDetail> selectByUserIdAndDateRange(
|
||||
@Param("userId") String userId,
|
||||
@Param("startDate") Date startDate,
|
||||
@Param("endDate") Date endDate);
|
||||
|
||||
/**
|
||||
* @description 根据用户ID和日期范围查询统计明细VO(带关联信息)
|
||||
* @param userId 用户ID
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return List<LearningStatisticsDetailVO> 统计明细VO列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<LearningStatisticsDetailVO> selectStatisticsDetailsWithInfo(
|
||||
@Param("userId") String userId,
|
||||
@Param("startDate") Date startDate,
|
||||
@Param("endDate") Date endDate);
|
||||
|
||||
/**
|
||||
* @description 根据用户ID、资源类型和日期查询统计明细
|
||||
* @param userId 用户ID
|
||||
* @param resourceType 资源类型
|
||||
* @param statDate 统计日期
|
||||
* @return TbLearningStatisticsDetail 统计明细
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
TbLearningStatisticsDetail selectByUserIdAndResourceTypeAndDate(
|
||||
@Param("userId") String userId,
|
||||
@Param("resourceType") Integer resourceType,
|
||||
@Param("resourceId") String resourceId,
|
||||
@Param("statDate") Date statDate);
|
||||
|
||||
/**
|
||||
* @description 删除统计明细(软删除)
|
||||
* @param id 明细ID
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int deleteStatisticsDetail(@Param("id") String id);
|
||||
|
||||
/**
|
||||
* @description 批量删除统计明细(软删除)
|
||||
* @param ids 明细ID列表
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
int batchDeleteStatisticsDetails(@Param("ids") List<String> ids);
|
||||
|
||||
/**
|
||||
* @description 按日期汇总用户学习统计
|
||||
* @param userId 用户ID
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return List<TbLearningStatisticsDetail> 汇总结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
List<TbLearningStatisticsDetail> selectDailySummary(
|
||||
@Param("userId") String userId,
|
||||
@Param("startDate") Date startDate,
|
||||
@Param("endDate") Date endDate);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.xyzh.study.service;
|
||||
|
||||
import org.xyzh.api.study.history.LearningHistoryAPI;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageDomain;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.study.TbLearningHistory;
|
||||
import org.xyzh.common.vo.LearningHistoryVO;
|
||||
import org.xyzh.common.vo.LearningStatisticsVO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 学习历史服务接口
|
||||
* @filename SCLearningHistoryService.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
public interface SCLearningHistoryService extends LearningHistoryAPI {
|
||||
|
||||
/**
|
||||
* @description 查询学习历史列表
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<List<LearningHistoryVO>> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<List<LearningHistoryVO>> getLearningHistories(TbLearningHistory filter);
|
||||
|
||||
/**
|
||||
* @description 分页查询学习历史
|
||||
* @param pageRequest 分页查询请求
|
||||
* @return ResultDomain<PageDomain<LearningHistoryVO>> 分页结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<PageDomain<LearningHistoryVO>> getLearningHistoriesPage(PageRequest<TbLearningHistory> pageRequest);
|
||||
|
||||
/**
|
||||
* @description 根据ID查询学习历史
|
||||
* @param id 历史记录ID
|
||||
* @return ResultDomain<TbLearningHistory> 学习历史
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<TbLearningHistory> getLearningHistoryById(String id);
|
||||
|
||||
/**
|
||||
* @description 获取用户某时间段的学习统计
|
||||
* @param userId 用户ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return ResultDomain<LearningStatisticsVO> 学习统计
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<LearningStatisticsVO> getUserLearningStatistics(String userId, Date startTime, Date endTime);
|
||||
|
||||
/**
|
||||
* @description 获取用户某时间段的学习统计(按周期)
|
||||
* @param userId 用户ID
|
||||
* @param periodType 周期类型(day/week/month)
|
||||
* @return ResultDomain<LearningStatisticsVO> 学习统计
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<LearningStatisticsVO> getUserLearningStatisticsByPeriod(String userId, String periodType);
|
||||
|
||||
/**
|
||||
* @description 获取当前用户的学习历史
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<List<LearningHistoryVO>> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<List<LearningHistoryVO>> getCurrentUserLearningHistories(TbLearningHistory filter);
|
||||
|
||||
/**
|
||||
* @description 获取当前用户的学习统计
|
||||
* @param periodType 周期类型(day/week/month)
|
||||
* @return ResultDomain<LearningStatisticsVO> 学习统计
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<LearningStatisticsVO> getCurrentUserLearningStatistics(String periodType);
|
||||
|
||||
/**
|
||||
* @description 删除学习历史
|
||||
* @param id 历史记录ID
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<Boolean> deleteLearningHistory(String id);
|
||||
|
||||
/**
|
||||
* @description 批量删除学习历史
|
||||
* @param ids 历史记录ID列表
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<Boolean> batchDeleteLearningHistories(List<String> ids);
|
||||
|
||||
/**
|
||||
* @description 获取用户最近的学习历史
|
||||
* @param userId 用户ID
|
||||
* @param limit 限制数量
|
||||
* @return ResultDomain<List<LearningHistoryVO>> 学习历史列表
|
||||
* @author yslg
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
ResultDomain<List<LearningHistoryVO>> getRecentLearningHistories(String userId, Integer limit);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,681 @@
|
||||
package org.xyzh.study.service.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.enums.AchievementEventType;
|
||||
import org.xyzh.common.core.event.AchievementEvent;
|
||||
import org.xyzh.common.core.page.PageDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.study.TbLearningHistory;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.common.vo.LearningHistoryVO;
|
||||
import org.xyzh.common.vo.LearningStatisticsDetailVO;
|
||||
import org.xyzh.common.vo.LearningStatisticsVO;
|
||||
import org.xyzh.study.mapper.LearningHistoryMapper;
|
||||
import org.xyzh.study.service.SCLearningHistoryService;
|
||||
import org.xyzh.system.utils.LoginUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @description 学习历史服务实现类
|
||||
* @filename SCLearningHistoryServiceImpl.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-27
|
||||
*/
|
||||
@Service
|
||||
public class SCLearningHistoryServiceImpl implements SCLearningHistoryService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SCLearningHistoryServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private LearningHistoryMapper learningHistoryMapper;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResultDomain<TbLearningHistory> recordLearningHistory(TbLearningHistory learningHistory) {
|
||||
ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
// 参数校验
|
||||
if (learningHistory.getUserID() == null || learningHistory.getUserID().isEmpty()) {
|
||||
TbSysUser currentUser = LoginUtil.getCurrentUser();
|
||||
if (currentUser == null) {
|
||||
resultDomain.fail("用户未登录");
|
||||
return resultDomain;
|
||||
}
|
||||
learningHistory.setUserID(currentUser.getID());
|
||||
}
|
||||
|
||||
if (learningHistory.getResourceType() == null) {
|
||||
resultDomain.fail("资源类型不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (learningHistory.getStartTime() == null) {
|
||||
learningHistory.setStartTime(new Date());
|
||||
}
|
||||
|
||||
// 计算时长
|
||||
if (learningHistory.getDuration() == null || learningHistory.getDuration() <= 0) {
|
||||
if (learningHistory.getEndTime() != null) {
|
||||
long duration = (learningHistory.getEndTime().getTime() - learningHistory.getStartTime().getTime()) / 1000;
|
||||
learningHistory.setDuration((int) duration);
|
||||
} else {
|
||||
learningHistory.setDuration(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是插入还是更新
|
||||
boolean isUpdate = false;
|
||||
if (learningHistory.getHistoryID() != null && !learningHistory.getHistoryID().isEmpty()) {
|
||||
isUpdate = true;
|
||||
}
|
||||
|
||||
int result;
|
||||
if (isUpdate) {
|
||||
// 更新已有记录
|
||||
result = learningHistoryMapper.updateLearningHistory(learningHistory);
|
||||
if (result > 0) {
|
||||
resultDomain.success("更新学习历史成功", learningHistory);
|
||||
logger.info("更新学习历史成功,historyID: {}, 用户ID: {}, 资源类型: {}, 时长: {}秒",
|
||||
learningHistory.getHistoryID(), learningHistory.getUserID(),
|
||||
learningHistory.getResourceType(), learningHistory.getDuration());
|
||||
|
||||
// 发布成就事件 - 学习时长更新
|
||||
publishLearningTimeEvent(learningHistory);
|
||||
} else {
|
||||
resultDomain.fail("更新学习历史失败");
|
||||
}
|
||||
} else {
|
||||
// 插入新记录
|
||||
learningHistory.setID(IDUtils.generateID());
|
||||
learningHistory.setHistoryID(IDUtils.generateID());
|
||||
learningHistory.setCreateTime(new Date());
|
||||
|
||||
result = learningHistoryMapper.insertLearningHistory(learningHistory);
|
||||
if (result > 0) {
|
||||
resultDomain.success("记录学习历史成功", learningHistory);
|
||||
logger.info("记录学习历史成功,ID: {}, 用户ID: {}, 资源类型: {}, 时长: {}秒",
|
||||
learningHistory.getID(), learningHistory.getUserID(),
|
||||
learningHistory.getResourceType(), learningHistory.getDuration());
|
||||
} else {
|
||||
resultDomain.fail("记录学习历史失败");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("记录学习历史异常", e);
|
||||
resultDomain.fail("记录学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResultDomain<Boolean> batchRecordLearningHistory(List<TbLearningHistory> historyList) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (historyList == null || historyList.isEmpty()) {
|
||||
resultDomain.fail("学习历史列表不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbSysUser currentUser = LoginUtil.getCurrentUser();
|
||||
Date now = new Date();
|
||||
|
||||
for (TbLearningHistory learningHistory : historyList) {
|
||||
if (learningHistory.getUserID() == null || learningHistory.getUserID().isEmpty()) {
|
||||
if (currentUser == null) {
|
||||
resultDomain.fail("用户未登录");
|
||||
return resultDomain;
|
||||
}
|
||||
learningHistory.setUserID(currentUser.getID());
|
||||
}
|
||||
if (learningHistory.getStartTime() == null) {
|
||||
learningHistory.setStartTime(now);
|
||||
}
|
||||
if (learningHistory.getID() == null || learningHistory.getID().isEmpty()) {
|
||||
learningHistory.setID(IDUtils.generateID());
|
||||
}
|
||||
if (learningHistory.getCreateTime() == null) {
|
||||
learningHistory.setCreateTime(now);
|
||||
}
|
||||
}
|
||||
|
||||
int result = learningHistoryMapper.batchInsertLearningHistories(historyList);
|
||||
if (result > 0) {
|
||||
resultDomain.success("批量记录学习历史成功", true);
|
||||
logger.info("批量记录学习历史成功,数量: {}", result);
|
||||
} else {
|
||||
resultDomain.fail("批量记录学习历史失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("批量记录学习历史异常", e);
|
||||
resultDomain.fail("批量记录学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<List<LearningHistoryVO>> getLearningHistories(TbLearningHistory filter) {
|
||||
ResultDomain<List<LearningHistoryVO>> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
List<LearningHistoryVO> historyVOList = learningHistoryMapper.selectLearningHistoriesWithDetails(filter);
|
||||
|
||||
// 格式化时长
|
||||
formatDuration(historyVOList);
|
||||
|
||||
resultDomain.success("查询学习历史成功", historyVOList);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询学习历史异常", e);
|
||||
resultDomain.fail("查询学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<PageDomain<LearningHistoryVO>> getLearningHistoriesPage(PageRequest<TbLearningHistory> pageRequest) {
|
||||
ResultDomain<PageDomain<LearningHistoryVO>> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
TbLearningHistory filter = pageRequest.getFilter();
|
||||
if (filter == null) {
|
||||
filter = new TbLearningHistory();
|
||||
}
|
||||
|
||||
// 分页参数
|
||||
PageParam pageParam = pageRequest.getPageParam();
|
||||
pageParam.setOffset((pageParam.getPageNumber() - 1) * pageParam.getPageSize());
|
||||
|
||||
// 查询总数
|
||||
long total = learningHistoryMapper.countLearningHistories(filter);
|
||||
|
||||
// 查询列表
|
||||
List<TbLearningHistory> historyList = learningHistoryMapper.selectLearningHistoriesPage(filter, pageParam);
|
||||
|
||||
// 转换为VO
|
||||
List<LearningHistoryVO> historyVOList = historyList.stream()
|
||||
.map(this::convertToVO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 格式化时长
|
||||
formatDuration(historyVOList);
|
||||
|
||||
// 构建分页结果
|
||||
PageDomain<LearningHistoryVO> pageDomain = new PageDomain<>();
|
||||
pageParam.setTotalElements(total);
|
||||
pageParam.setTotalPages((int) Math.ceil((double) total / pageParam.getPageSize()));
|
||||
pageDomain.setPageParam(pageParam);
|
||||
pageDomain.setDataList(historyVOList);
|
||||
|
||||
resultDomain.success("分页查询学习历史成功", pageDomain);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("分页查询学习历史异常", e);
|
||||
resultDomain.fail("分页查询学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbLearningHistory> getLearningHistoryById(String id) {
|
||||
ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (id == null || id.isEmpty()) {
|
||||
resultDomain.fail("历史记录ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbLearningHistory learningHistory = learningHistoryMapper.selectById(id);
|
||||
if (learningHistory != null) {
|
||||
resultDomain.success("查询学习历史成功", learningHistory);
|
||||
} else {
|
||||
resultDomain.fail("学习历史不存在");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询学习历史异常", e);
|
||||
resultDomain.fail("查询学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<LearningStatisticsVO> getUserLearningStatistics(String userId, Date startTime, Date endTime) {
|
||||
ResultDomain<LearningStatisticsVO> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (userId == null || userId.isEmpty()) {
|
||||
resultDomain.fail("用户ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (startTime == null || endTime == null) {
|
||||
resultDomain.fail("开始时间和结束时间不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 统计总体数据
|
||||
Map<String, Object> statistics = learningHistoryMapper.selectLearningStatisticsByTimeRange(userId, startTime, endTime);
|
||||
|
||||
// 获取学习的资源列表
|
||||
List<Map<String, Object>> learnedResources = learningHistoryMapper.selectLearnedResourcesByTimeRange(userId, startTime, endTime);
|
||||
|
||||
// 构建VO
|
||||
LearningStatisticsVO statisticsVO = new LearningStatisticsVO();
|
||||
statisticsVO.setUserID(userId);
|
||||
|
||||
if (statistics != null) {
|
||||
statisticsVO.setTotalDuration(getIntValue(statistics, "totalDuration"));
|
||||
statisticsVO.setLearnCount(getIntValue(statistics, "learnCount"));
|
||||
statisticsVO.setLearnDays(getIntValue(statistics, "learnDays"));
|
||||
statisticsVO.setResourceCount(getIntValue(statistics, "resourceCount"));
|
||||
statisticsVO.setCourseCount(getIntValue(statistics, "courseCount"));
|
||||
|
||||
// 格式化时长
|
||||
statisticsVO.setTotalDurationFormatted(formatDurationString(statisticsVO.getTotalDuration()));
|
||||
|
||||
// 计算平均每天学习时长
|
||||
if (statisticsVO.getLearnDays() > 0) {
|
||||
statisticsVO.setAvgDailyDuration(statisticsVO.getTotalDuration() / statisticsVO.getLearnDays());
|
||||
}
|
||||
}
|
||||
|
||||
resultDomain.success("查询学习统计成功", statisticsVO);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询学习统计异常", e);
|
||||
resultDomain.fail("查询学习统计异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<LearningStatisticsVO> getUserLearningStatisticsByPeriod(String userId, String periodType) {
|
||||
ResultDomain<LearningStatisticsVO> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (userId == null || userId.isEmpty()) {
|
||||
resultDomain.fail("用户ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 计算时间范围
|
||||
Date endTime = new Date();
|
||||
Date startTime = calculateStartTime(endTime, periodType);
|
||||
|
||||
if (startTime == null) {
|
||||
resultDomain.fail("无效的周期类型");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
ResultDomain<LearningStatisticsVO> statistics = getUserLearningStatistics(userId, startTime, endTime);
|
||||
if (statistics.isSuccess() && statistics.getData() != null) {
|
||||
statistics.getData().setPeriod(periodType);
|
||||
}
|
||||
|
||||
return statistics;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询学习统计异常", e);
|
||||
resultDomain.fail("查询学习统计异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<List<LearningHistoryVO>> getCurrentUserLearningHistories(TbLearningHistory filter) {
|
||||
ResultDomain<List<LearningHistoryVO>> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
TbSysUser currentUser = LoginUtil.getCurrentUser();
|
||||
if (currentUser == null) {
|
||||
resultDomain.fail("用户未登录");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (filter == null) {
|
||||
filter = new TbLearningHistory();
|
||||
}
|
||||
filter.setUserID(currentUser.getID());
|
||||
return getLearningHistories(filter);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询当前用户学习历史异常", e);
|
||||
resultDomain.fail("查询当前用户学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<LearningStatisticsVO> getCurrentUserLearningStatistics(String periodType) {
|
||||
ResultDomain<LearningStatisticsVO> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
TbSysUser currentUser = LoginUtil.getCurrentUser();
|
||||
if (currentUser == null) {
|
||||
resultDomain.fail("用户未登录");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
return getUserLearningStatisticsByPeriod(currentUser.getID(), periodType);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询当前用户学习统计异常", e);
|
||||
resultDomain.fail("查询当前用户学习统计异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResultDomain<Boolean> deleteLearningHistory(String id) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (id == null || id.isEmpty()) {
|
||||
resultDomain.fail("历史记录ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
int result = learningHistoryMapper.deleteLearningHistory(id);
|
||||
if (result > 0) {
|
||||
resultDomain.success("删除学习历史成功", true);
|
||||
} else {
|
||||
resultDomain.fail("删除学习历史失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("删除学习历史异常", e);
|
||||
resultDomain.fail("删除学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResultDomain<Boolean> batchDeleteLearningHistories(List<String> ids) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
resultDomain.fail("历史记录ID列表不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
int result = learningHistoryMapper.batchDeleteLearningHistories(ids);
|
||||
if (result > 0) {
|
||||
resultDomain.success("批量删除学习历史成功", true);
|
||||
} else {
|
||||
resultDomain.fail("批量删除学习历史失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("批量删除学习历史异常", e);
|
||||
resultDomain.fail("批量删除学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<List<LearningHistoryVO>> getRecentLearningHistories(String userId, Integer limit) {
|
||||
ResultDomain<List<LearningHistoryVO>> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
if (userId == null || userId.isEmpty()) {
|
||||
resultDomain.fail("用户ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (limit == null || limit <= 0) {
|
||||
limit = 10;
|
||||
}
|
||||
|
||||
List<TbLearningHistory> historyList = learningHistoryMapper.selectRecentByUserId(userId, limit);
|
||||
List<LearningHistoryVO> historyVOList = historyList.stream()
|
||||
.map(this::convertToVO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
formatDuration(historyVOList);
|
||||
|
||||
resultDomain.success("查询最近学习历史成功", historyVOList);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("查询最近学习历史异常", e);
|
||||
resultDomain.fail("查询最近学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbLearningHistory> recordResourceView(String userId, String resourceId, Integer duration) {
|
||||
ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
TbLearningHistory learningHistory = new TbLearningHistory();
|
||||
learningHistory.setUserID(userId);
|
||||
learningHistory.setResourceType(1); // 1=资源/新闻
|
||||
learningHistory.setResourceID(resourceId);
|
||||
learningHistory.setDuration(duration);
|
||||
learningHistory.setStartTime(new Date());
|
||||
|
||||
return recordLearningHistory(learningHistory);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("记录资源观看历史异常", e);
|
||||
resultDomain.fail("记录资源观看历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbLearningHistory> recordCourseLearn(String userId, String courseId, String chapterId, String nodeId, Integer duration) {
|
||||
ResultDomain<TbLearningHistory> resultDomain = new ResultDomain<>();
|
||||
|
||||
try {
|
||||
TbLearningHistory learningHistory = new TbLearningHistory();
|
||||
learningHistory.setUserID(userId);
|
||||
|
||||
// 根据提供的信息确定资源类型
|
||||
if (nodeId != null && !nodeId.isEmpty()) {
|
||||
learningHistory.setResourceType(4); // 4=节点
|
||||
learningHistory.setNodeID(nodeId);
|
||||
} else if (chapterId != null && !chapterId.isEmpty()) {
|
||||
learningHistory.setResourceType(3); // 3=章节
|
||||
learningHistory.setChapterID(chapterId);
|
||||
} else {
|
||||
learningHistory.setResourceType(2); // 2=课程
|
||||
}
|
||||
|
||||
learningHistory.setCourseID(courseId);
|
||||
learningHistory.setChapterID(chapterId);
|
||||
learningHistory.setNodeID(nodeId);
|
||||
learningHistory.setDuration(duration);
|
||||
learningHistory.setStartTime(new Date());
|
||||
|
||||
return recordLearningHistory(learningHistory);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("记录课程学习历史异常", e);
|
||||
resultDomain.fail("记录课程学习历史异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// ==================== 私有辅助方法 ====================
|
||||
|
||||
/**
|
||||
* 发布学习时长更新事件
|
||||
*/
|
||||
private void publishLearningTimeEvent(TbLearningHistory learningHistory) {
|
||||
try {
|
||||
// 构建成就事件
|
||||
AchievementEvent event = AchievementEvent.builder(
|
||||
learningHistory.getUserID(),
|
||||
AchievementEventType.LEARNING_TIME_UPDATED
|
||||
)
|
||||
.value(learningHistory.getDuration()) // 学习时长(秒)
|
||||
.extra("resourceType", learningHistory.getResourceType())
|
||||
.extra("resourceID", learningHistory.getResourceID())
|
||||
.extra("courseID", learningHistory.getCourseID())
|
||||
.extra("historyID", learningHistory.getHistoryID())
|
||||
.build();
|
||||
|
||||
// 发布事件(异步处理)
|
||||
eventPublisher.publishEvent(event);
|
||||
|
||||
logger.debug("发布学习时长更新事件,用户ID: {}, 时长: {}秒",
|
||||
learningHistory.getUserID(), learningHistory.getDuration());
|
||||
} catch (Exception e) {
|
||||
// 成就事件发布失败不应该影响主业务
|
||||
logger.error("发布学习时长事件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换实体为VO
|
||||
*/
|
||||
private LearningHistoryVO convertToVO(TbLearningHistory entity) {
|
||||
LearningHistoryVO vo = new LearningHistoryVO();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
|
||||
// 设置资源类型名称
|
||||
if (entity.getResourceType() != null) {
|
||||
vo.setResourceTypeName(getResourceTypeName(entity.getResourceType()));
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时长列表
|
||||
*/
|
||||
private void formatDuration(List<LearningHistoryVO> historyVOList) {
|
||||
if (historyVOList != null) {
|
||||
for (LearningHistoryVO vo : historyVOList) {
|
||||
if (vo.getDuration() != null) {
|
||||
vo.setDurationFormatted(formatDurationString(vo.getDuration()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时长(秒转为可读字符串)
|
||||
*/
|
||||
private String formatDurationString(Integer seconds) {
|
||||
if (seconds == null || seconds == 0) {
|
||||
return "0秒";
|
||||
}
|
||||
|
||||
int hours = seconds / 3600;
|
||||
int minutes = (seconds % 3600) / 60;
|
||||
int secs = seconds % 60;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (hours > 0) {
|
||||
sb.append(hours).append("小时");
|
||||
}
|
||||
if (minutes > 0) {
|
||||
sb.append(minutes).append("分钟");
|
||||
}
|
||||
if (secs > 0 || sb.length() == 0) {
|
||||
sb.append(secs).append("秒");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源类型名称
|
||||
*/
|
||||
private String getResourceTypeName(Integer resourceType) {
|
||||
switch (resourceType) {
|
||||
case 1:
|
||||
return "资源/新闻";
|
||||
case 2:
|
||||
return "课程";
|
||||
case 3:
|
||||
return "章节";
|
||||
case 4:
|
||||
return "节点";
|
||||
default:
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算开始时间
|
||||
*/
|
||||
private Date calculateStartTime(Date endTime, String periodType) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(endTime);
|
||||
|
||||
if ("day".equalsIgnoreCase(periodType)) {
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -1);
|
||||
} else if ("week".equalsIgnoreCase(periodType)) {
|
||||
calendar.add(Calendar.WEEK_OF_YEAR, -1);
|
||||
} else if ("month".equalsIgnoreCase(periodType)) {
|
||||
calendar.add(Calendar.MONTH, -1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Map中获取Integer值
|
||||
*/
|
||||
private Integer getIntValue(Map<String, Object> map, String key) {
|
||||
Object value = map.get(key);
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return ((Long) value).intValue();
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return ((BigDecimal) value).intValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
<?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.xyzh.study.mapper.LearningHistoryMapper">
|
||||
|
||||
<!-- 基础结果映射 -->
|
||||
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.study.TbLearningHistory">
|
||||
<id column="id" property="id" jdbcType="VARCHAR"/>
|
||||
<result column="user_id" property="userID" jdbcType="VARCHAR"/>
|
||||
<result column="history_id" property="historyID" jdbcType="VARCHAR"/>
|
||||
<result column="resource_type" property="resourceType" jdbcType="INTEGER"/>
|
||||
<result column="resource_id" property="resourceID" jdbcType="VARCHAR"/>
|
||||
<result column="course_id" property="courseID" jdbcType="VARCHAR"/>
|
||||
<result column="chapter_id" property="chapterID" jdbcType="VARCHAR"/>
|
||||
<result column="node_id" property="nodeID" jdbcType="VARCHAR"/>
|
||||
<result column="task_id" property="taskID" jdbcType="VARCHAR"/>
|
||||
<result column="start_time" property="startTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="end_time" property="endTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="duration" property="duration" jdbcType="INTEGER"/>
|
||||
<result column="start_progress" property="startProgress" jdbcType="DECIMAL"/>
|
||||
<result column="end_progress" property="endProgress" jdbcType="DECIMAL"/>
|
||||
<result column="device_type" property="deviceType" jdbcType="VARCHAR"/>
|
||||
<result column="ip_address" property="ipAddress" jdbcType="VARCHAR"/>
|
||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="deleted" property="deleted" jdbcType="BOOLEAN"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- VO结果映射(带关联信息) -->
|
||||
<resultMap id="VOResultMap" type="org.xyzh.common.vo.LearningHistoryVO">
|
||||
<id column="id" property="id" jdbcType="VARCHAR"/>
|
||||
<result column="user_id" property="userID" jdbcType="VARCHAR"/>
|
||||
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
|
||||
<result column="history_id" property="historyID" jdbcType="VARCHAR"/>
|
||||
<result column="resource_type" property="resourceType" jdbcType="INTEGER"/>
|
||||
<result column="resource_id" property="resourceID" jdbcType="VARCHAR"/>
|
||||
<result column="resource_title" property="resourceTitle" jdbcType="VARCHAR"/>
|
||||
<result column="course_id" property="courseID" jdbcType="VARCHAR"/>
|
||||
<result column="course_name" property="courseName" jdbcType="VARCHAR"/>
|
||||
<result column="chapter_id" property="chapterID" jdbcType="VARCHAR"/>
|
||||
<result column="chapter_name" property="chapterName" jdbcType="VARCHAR"/>
|
||||
<result column="node_id" property="nodeID" jdbcType="VARCHAR"/>
|
||||
<result column="node_name" property="nodeName" jdbcType="VARCHAR"/>
|
||||
<result column="task_id" property="taskID" jdbcType="VARCHAR"/>
|
||||
<result column="task_name" property="taskName" jdbcType="VARCHAR"/>
|
||||
<result column="start_time" property="startTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="end_time" property="endTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="duration" property="duration" jdbcType="INTEGER"/>
|
||||
<result column="start_progress" property="startProgress" jdbcType="DECIMAL"/>
|
||||
<result column="end_progress" property="endProgress" jdbcType="DECIMAL"/>
|
||||
<result column="device_type" property="deviceType" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 基础字段 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, user_id, history_id, resource_type, resource_id, course_id, chapter_id, node_id, task_id,
|
||||
start_time, end_time, duration, start_progress, end_progress, device_type, ip_address,
|
||||
creator, create_time, deleted
|
||||
</sql>
|
||||
|
||||
<!-- 通用条件 -->
|
||||
<sql id="Where_Clause">
|
||||
<where>
|
||||
deleted = 0
|
||||
<if test="userID != null and userID != ''">
|
||||
AND user_id = #{userID}
|
||||
</if>
|
||||
<if test="historyID != null and historyID != ''">
|
||||
AND history_id = #{historyID}
|
||||
</if>
|
||||
<if test="resourceType != null">
|
||||
AND resource_type = #{resourceType}
|
||||
</if>
|
||||
<if test="resourceID != null and resourceID != ''">
|
||||
AND resource_id = #{resourceID}
|
||||
</if>
|
||||
<if test="courseID != null and courseID != ''">
|
||||
AND course_id = #{courseID}
|
||||
</if>
|
||||
<if test="chapterID != null and chapterID != ''">
|
||||
AND chapter_id = #{chapterID}
|
||||
</if>
|
||||
<if test="nodeID != null and nodeID != ''">
|
||||
AND node_id = #{nodeID}
|
||||
</if>
|
||||
<if test="taskID != null and taskID != ''">
|
||||
AND task_id = #{taskID}
|
||||
</if>
|
||||
<if test="deviceType != null and deviceType != ''">
|
||||
AND device_type = #{deviceType}
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 插入学习历史 -->
|
||||
<insert id="insertLearningHistory">
|
||||
INSERT INTO tb_learning_history (
|
||||
id, user_id, history_id, resource_type, resource_id, course_id, chapter_id, node_id, task_id,
|
||||
start_time, end_time, duration, start_progress, end_progress, device_type, ip_address,
|
||||
creator, create_time, deleted
|
||||
) VALUES (
|
||||
#{id}, #{userID}, #{historyID}, #{resourceType}, #{resourceID}, #{courseID}, #{chapterID}, #{nodeID}, #{taskID},
|
||||
#{startTime}, #{endTime}, #{duration}, #{startProgress}, #{endProgress}, #{deviceType}, #{ipAddress},
|
||||
#{creator}, #{createTime}, 0
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 更新学习历史 -->
|
||||
<update id="updateLearningHistory">
|
||||
UPDATE tb_learning_history
|
||||
<set>
|
||||
<if test="endTime != null">
|
||||
end_time = #{endTime},
|
||||
</if>
|
||||
<if test="duration != null">
|
||||
duration = #{duration},
|
||||
</if>
|
||||
<if test="startProgress != null">
|
||||
start_progress = #{startProgress},
|
||||
</if>
|
||||
<if test="endProgress != null">
|
||||
end_progress = #{endProgress},
|
||||
</if>
|
||||
<if test="deviceType != null">
|
||||
device_type = #{deviceType},
|
||||
</if>
|
||||
<if test="ipAddress != null">
|
||||
ip_address = #{ipAddress},
|
||||
</if>
|
||||
</set>
|
||||
WHERE history_id = #{historyID} AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 批量插入学习历史 -->
|
||||
<insert id="batchInsertLearningHistories">
|
||||
INSERT INTO tb_learning_history (
|
||||
id, user_id, history_id, resource_type, resource_id, course_id, chapter_id, node_id, task_id,
|
||||
start_time, end_time, duration, start_progress, end_progress, device_type, ip_address,
|
||||
creator, create_time, deleted
|
||||
) VALUES
|
||||
<foreach collection="historyList" item="item" separator=",">
|
||||
(
|
||||
#{item.id}, #{item.userID}, #{item.historyID}, #{item.resourceType}, #{item.resourceID},
|
||||
#{item.courseID}, #{item.chapterID}, #{item.nodeID}, #{item.taskID},
|
||||
#{item.startTime}, #{item.endTime}, #{item.duration}, #{item.startProgress}, #{item.endProgress},
|
||||
#{item.deviceType}, #{item.ipAddress}, #{item.creator}, #{item.createTime}, 0
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 根据ID查询 -->
|
||||
<select id="selectById" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
WHERE id = #{id} AND deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID查询 -->
|
||||
<select id="selectByUserId" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId} AND deleted = 0
|
||||
ORDER BY start_time DESC, create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据条件查询学习历史列表 -->
|
||||
<select id="selectLearningHistories" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
<include refid="Where_Clause"/>
|
||||
ORDER BY start_time DESC, create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据条件查询学习历史VO列表(带关联信息) -->
|
||||
<select id="selectLearningHistoriesWithDetails" resultMap="VOResultMap">
|
||||
SELECT
|
||||
lh.id,
|
||||
lh.user_id,
|
||||
u.username as user_name,
|
||||
lh.history_id,
|
||||
lh.resource_type,
|
||||
lh.resource_id,
|
||||
CASE
|
||||
WHEN lh.resource_type = 1 THEN r.title
|
||||
WHEN lh.resource_type = 2 THEN c.name
|
||||
WHEN lh.resource_type = 3 THEN ch.name
|
||||
WHEN lh.resource_type = 4 THEN n.name
|
||||
END as resource_title,
|
||||
lh.course_id,
|
||||
c.name as course_name,
|
||||
lh.chapter_id,
|
||||
ch.name as chapter_name,
|
||||
lh.node_id,
|
||||
n.name as node_name,
|
||||
lh.task_id,
|
||||
t.name as task_name,
|
||||
lh.start_time,
|
||||
lh.end_time,
|
||||
lh.duration,
|
||||
lh.start_progress,
|
||||
lh.end_progress,
|
||||
lh.device_type,
|
||||
lh.create_time
|
||||
FROM tb_learning_history lh
|
||||
LEFT JOIN tb_sys_user u ON lh.user_id = u.id
|
||||
LEFT JOIN tb_resource r ON lh.resource_type = 1 AND lh.resource_id = r.resource_id
|
||||
LEFT JOIN tb_course c ON lh.course_id = c.course_id
|
||||
LEFT JOIN tb_course_chapter ch ON lh.chapter_id = ch.chapter_id
|
||||
LEFT JOIN tb_course_node n ON lh.node_id = n.node_id
|
||||
LEFT JOIN tb_learning_task t ON lh.task_id = t.task_id
|
||||
<include refid="Where_Clause"/>
|
||||
ORDER BY lh.start_time DESC, lh.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 分页查询学习历史 -->
|
||||
<select id="selectLearningHistoriesPage" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
<include refid="Where_Clause"/>
|
||||
ORDER BY start_time DESC, create_time DESC
|
||||
LIMIT #{pageParam.offset}, #{pageParam.pageSize}
|
||||
</select>
|
||||
|
||||
<!-- 统计学习历史总数 -->
|
||||
<select id="countLearningHistories" resultType="long">
|
||||
SELECT COUNT(*)
|
||||
FROM tb_learning_history
|
||||
<include refid="Where_Clause"/>
|
||||
</select>
|
||||
|
||||
<!-- 根据时间段查询学习历史 -->
|
||||
<select id="selectByUserIdAndTimeRange" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId}
|
||||
AND start_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND deleted = 0
|
||||
ORDER BY start_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据时间段和资源类型查询学习历史 -->
|
||||
<select id="selectByUserIdAndResourceTypeAndTimeRange" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId}
|
||||
AND resource_type = #{resourceType}
|
||||
AND start_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND deleted = 0
|
||||
ORDER BY start_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 统计用户某时间段的学习时长 -->
|
||||
<select id="selectLearningStatisticsByTimeRange" resultType="map">
|
||||
SELECT
|
||||
SUM(duration) as totalDuration,
|
||||
COUNT(*) as learnCount,
|
||||
COUNT(DISTINCT DATE(start_time)) as learnDays,
|
||||
COUNT(DISTINCT CASE WHEN resource_type = 1 THEN resource_id END) as resourceCount,
|
||||
COUNT(DISTINCT CASE WHEN resource_type = 2 THEN course_id END) as courseCount
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId}
|
||||
AND start_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- 统计用户某时间段各资源类型的学习时长 -->
|
||||
<select id="selectLearningStatisticsByResourceType" resultType="map">
|
||||
SELECT
|
||||
resource_type as resourceType,
|
||||
SUM(duration) as totalDuration,
|
||||
COUNT(*) as learnCount,
|
||||
COUNT(DISTINCT resource_id) as resourceCount
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId}
|
||||
AND start_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND deleted = 0
|
||||
GROUP BY resource_type
|
||||
ORDER BY resource_type
|
||||
</select>
|
||||
|
||||
<!-- 获取用户学习的资源列表(按时间段) -->
|
||||
<select id="selectLearnedResourcesByTimeRange" resultType="map">
|
||||
SELECT
|
||||
resource_type as resourceType,
|
||||
resource_id as resourceId,
|
||||
course_id as courseId,
|
||||
chapter_id as chapterId,
|
||||
node_id as nodeId,
|
||||
SUM(duration) as totalDuration,
|
||||
COUNT(*) as learnCount,
|
||||
MAX(start_time) as lastLearnTime
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId}
|
||||
AND start_time BETWEEN #{startTime} AND #{endTime}
|
||||
AND deleted = 0
|
||||
GROUP BY resource_type, resource_id, course_id, chapter_id, node_id
|
||||
ORDER BY lastLearnTime DESC
|
||||
</select>
|
||||
|
||||
<!-- 删除学习历史(软删除) -->
|
||||
<update id="deleteLearningHistory">
|
||||
UPDATE tb_learning_history
|
||||
SET deleted = 1, delete_time = NOW()
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<!-- 批量删除学习历史(软删除) -->
|
||||
<update id="batchDeleteLearningHistories">
|
||||
UPDATE tb_learning_history
|
||||
SET deleted = 1, delete_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<!-- 根据会话ID查询学习历史 -->
|
||||
<select id="selectByhistoryID" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
WHERE history_id = #{historyID} AND deleted = 0
|
||||
ORDER BY start_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 获取用户最近的学习历史 -->
|
||||
<select id="selectRecentByUserId" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_history
|
||||
WHERE user_id = #{userId} AND deleted = 0
|
||||
ORDER BY start_time DESC, create_time DESC
|
||||
LIMIT #{limit}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,246 @@
|
||||
<?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.xyzh.study.mapper.LearningStatisticsDetailMapper">
|
||||
|
||||
<!-- 基础结果映射 -->
|
||||
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.study.TbLearningStatisticsDetail">
|
||||
<id column="id" property="id" jdbcType="VARCHAR"/>
|
||||
<result column="user_id" property="userID" jdbcType="VARCHAR"/>
|
||||
<result column="stat_date" property="statDate" jdbcType="DATE"/>
|
||||
<result column="resource_type" property="resourceType" jdbcType="INTEGER"/>
|
||||
<result column="resource_id" property="resourceID" jdbcType="VARCHAR"/>
|
||||
<result column="course_id" property="courseID" jdbcType="VARCHAR"/>
|
||||
<result column="chapter_id" property="chapterID" jdbcType="VARCHAR"/>
|
||||
<result column="total_duration" property="totalDuration" jdbcType="INTEGER"/>
|
||||
<result column="learn_count" property="learnCount" jdbcType="INTEGER"/>
|
||||
<result column="is_complete" property="isComplete" jdbcType="BOOLEAN"/>
|
||||
<result column="complete_time" property="completeTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
||||
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="deleted" property="deleted" jdbcType="BOOLEAN"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- VO结果映射(带关联信息) -->
|
||||
<resultMap id="VOResultMap" type="org.xyzh.common.vo.LearningStatisticsDetailVO">
|
||||
<result column="stat_date" property="statDate" jdbcType="DATE"/>
|
||||
<result column="resource_type" property="resourceType" jdbcType="INTEGER"/>
|
||||
<result column="resource_id" property="resourceID" jdbcType="VARCHAR"/>
|
||||
<result column="resource_title" property="resourceTitle" jdbcType="VARCHAR"/>
|
||||
<result column="course_id" property="courseID" jdbcType="VARCHAR"/>
|
||||
<result column="course_name" property="courseName" jdbcType="VARCHAR"/>
|
||||
<result column="chapter_id" property="chapterID" jdbcType="VARCHAR"/>
|
||||
<result column="chapter_name" property="chapterName" jdbcType="VARCHAR"/>
|
||||
<result column="total_duration" property="totalDuration" jdbcType="INTEGER"/>
|
||||
<result column="learn_count" property="learnCount" jdbcType="INTEGER"/>
|
||||
<result column="is_complete" property="isComplete" jdbcType="BOOLEAN"/>
|
||||
<result column="complete_time" property="completeTime" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 基础字段 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, user_id, stat_date, resource_type, resource_id, course_id, chapter_id,
|
||||
total_duration, learn_count, is_complete, complete_time,
|
||||
creator, updater, create_time, update_time, deleted
|
||||
</sql>
|
||||
|
||||
<!-- 通用条件 -->
|
||||
<sql id="Where_Clause">
|
||||
<where>
|
||||
deleted = 0
|
||||
<if test="userID != null and userID != ''">
|
||||
AND user_id = #{userID}
|
||||
</if>
|
||||
<if test="statDate != null">
|
||||
AND stat_date = #{statDate}
|
||||
</if>
|
||||
<if test="resourceType != null">
|
||||
AND resource_type = #{resourceType}
|
||||
</if>
|
||||
<if test="resourceID != null and resourceID != ''">
|
||||
AND resource_id = #{resourceID}
|
||||
</if>
|
||||
<if test="courseID != null and courseID != ''">
|
||||
AND course_id = #{courseID}
|
||||
</if>
|
||||
<if test="chapterID != null and chapterID != ''">
|
||||
AND chapter_id = #{chapterID}
|
||||
</if>
|
||||
<if test="isComplete != null">
|
||||
AND is_complete = #{isComplete}
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 插入统计明细 -->
|
||||
<insert id="insertStatisticsDetail">
|
||||
INSERT INTO tb_learning_statistics_detail (
|
||||
id, user_id, stat_date, resource_type, resource_id, course_id, chapter_id,
|
||||
total_duration, learn_count, is_complete, complete_time,
|
||||
creator, create_time, deleted
|
||||
) VALUES (
|
||||
#{id}, #{userID}, #{statDate}, #{resourceType}, #{resourceID}, #{courseID}, #{chapterID},
|
||||
#{totalDuration}, #{learnCount}, #{isComplete}, #{completeTime},
|
||||
#{creator}, #{createTime}, 0
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 更新统计明细 -->
|
||||
<update id="updateStatisticsDetail">
|
||||
UPDATE tb_learning_statistics_detail
|
||||
<set>
|
||||
<if test="totalDuration != null">
|
||||
total_duration = #{totalDuration},
|
||||
</if>
|
||||
<if test="learnCount != null">
|
||||
learn_count = #{learnCount},
|
||||
</if>
|
||||
<if test="isComplete != null">
|
||||
is_complete = #{isComplete},
|
||||
</if>
|
||||
<if test="completeTime != null">
|
||||
complete_time = #{completeTime},
|
||||
</if>
|
||||
<if test="updater != null">
|
||||
updater = #{updater},
|
||||
</if>
|
||||
update_time = NOW()
|
||||
</set>
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<!-- 插入或更新统计明细(ON DUPLICATE KEY UPDATE) -->
|
||||
<insert id="insertOrUpdateStatisticsDetail">
|
||||
INSERT INTO tb_learning_statistics_detail (
|
||||
id, user_id, stat_date, resource_type, resource_id, course_id, chapter_id,
|
||||
total_duration, learn_count, is_complete, complete_time,
|
||||
creator, create_time, deleted
|
||||
) VALUES (
|
||||
#{id}, #{userID}, #{statDate}, #{resourceType}, #{resourceID}, #{courseID}, #{chapterID},
|
||||
#{totalDuration}, #{learnCount}, #{isComplete}, #{completeTime},
|
||||
#{creator}, NOW(), 0
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
total_duration = total_duration + #{totalDuration},
|
||||
learn_count = learn_count + #{learnCount},
|
||||
is_complete = #{isComplete},
|
||||
complete_time = #{completeTime},
|
||||
updater = #{updater},
|
||||
update_time = NOW()
|
||||
</insert>
|
||||
|
||||
<!-- 根据条件查询统计明细 -->
|
||||
<select id="selectStatisticsDetails" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_statistics_detail
|
||||
<include refid="Where_Clause"/>
|
||||
ORDER BY stat_date DESC, create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID和日期查询统计明细 -->
|
||||
<select id="selectByUserIdAndDate" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_statistics_detail
|
||||
WHERE user_id = #{userId}
|
||||
AND stat_date = #{statDate}
|
||||
AND deleted = 0
|
||||
ORDER BY resource_type, total_duration DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID和日期范围查询统计明细 -->
|
||||
<select id="selectByUserIdAndDateRange" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_statistics_detail
|
||||
WHERE user_id = #{userId}
|
||||
AND stat_date BETWEEN #{startDate} AND #{endDate}
|
||||
AND deleted = 0
|
||||
ORDER BY stat_date DESC, resource_type, total_duration DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID和日期范围查询统计明细VO(带关联信息) -->
|
||||
<select id="selectStatisticsDetailsWithInfo" resultMap="VOResultMap">
|
||||
SELECT
|
||||
sd.stat_date,
|
||||
sd.resource_type,
|
||||
sd.resource_id,
|
||||
CASE
|
||||
WHEN sd.resource_type = 1 THEN r.title
|
||||
WHEN sd.resource_type = 2 THEN c.name
|
||||
WHEN sd.resource_type = 3 THEN ch.name
|
||||
END as resource_title,
|
||||
sd.course_id,
|
||||
c.name as course_name,
|
||||
sd.chapter_id,
|
||||
ch.name as chapter_name,
|
||||
sd.total_duration,
|
||||
sd.learn_count,
|
||||
sd.is_complete,
|
||||
sd.complete_time
|
||||
FROM tb_learning_statistics_detail sd
|
||||
LEFT JOIN tb_resource r ON sd.resource_type = 1 AND sd.resource_id = r.resource_id
|
||||
LEFT JOIN tb_course c ON sd.course_id = c.course_id
|
||||
LEFT JOIN tb_course_chapter ch ON sd.chapter_id = ch.chapter_id
|
||||
WHERE sd.user_id = #{userId}
|
||||
AND sd.stat_date BETWEEN #{startDate} AND #{endDate}
|
||||
AND sd.deleted = 0
|
||||
ORDER BY sd.stat_date DESC, sd.total_duration DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID、资源类型和日期查询统计明细 -->
|
||||
<select id="selectByUserIdAndResourceTypeAndDate" resultMap="BaseResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM tb_learning_statistics_detail
|
||||
WHERE user_id = #{userId}
|
||||
AND resource_type = #{resourceType}
|
||||
AND resource_id = #{resourceId}
|
||||
AND stat_date = #{statDate}
|
||||
AND deleted = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 删除统计明细(软删除) -->
|
||||
<update id="deleteStatisticsDetail">
|
||||
UPDATE tb_learning_statistics_detail
|
||||
SET deleted = 1, delete_time = NOW()
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<!-- 批量删除统计明细(软删除) -->
|
||||
<update id="batchDeleteStatisticsDetails">
|
||||
UPDATE tb_learning_statistics_detail
|
||||
SET deleted = 1, delete_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<!-- 按日期汇总用户学习统计 -->
|
||||
<select id="selectDailySummary" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
NULL as id,
|
||||
user_id,
|
||||
stat_date,
|
||||
NULL as resource_type,
|
||||
NULL as resource_id,
|
||||
NULL as course_id,
|
||||
NULL as chapter_id,
|
||||
SUM(total_duration) as total_duration,
|
||||
SUM(learn_count) as learn_count,
|
||||
NULL as is_complete,
|
||||
NULL as complete_time,
|
||||
NULL as creator,
|
||||
NULL as updater,
|
||||
MIN(create_time) as create_time,
|
||||
MAX(update_time) as update_time,
|
||||
0 as deleted
|
||||
FROM tb_learning_statistics_detail
|
||||
WHERE user_id = #{userId}
|
||||
AND stat_date BETWEEN #{startDate} AND #{endDate}
|
||||
AND deleted = 0
|
||||
GROUP BY user_id, stat_date
|
||||
ORDER BY stat_date DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user