Ver Fonte

feat: 1、看课评论基础功能完成;2、添加配置是否开启评论;

caoliqin há 1 semana atrás
pai
commit
7c411de8e7

+ 103 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java

@@ -0,0 +1,103 @@
+package com.fs.course.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.course.domain.FsCourseWatchComment;
+import com.fs.course.service.IFsCourseWatchCommentService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 看课评论Controller
+ * 
+ * @author fs
+ * @date 2025-05-26
+ */
+@RestController
+@RequestMapping("/course/courseWatchComment")
+public class FsCourseWatchCommentController extends BaseController
+{
+    @Autowired
+    private IFsCourseWatchCommentService fsCourseWatchCommentService;
+
+    /**
+     * 查询看课评论列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseWatchComment fsCourseWatchComment)
+    {
+        startPage();
+        List<FsCourseWatchComment> list = fsCourseWatchCommentService.selectFsCourseWatchCommentList(fsCourseWatchComment);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出看课评论列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:export')")
+    @Log(title = "看课评论", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseWatchComment fsCourseWatchComment)
+    {
+        List<FsCourseWatchComment> list = fsCourseWatchCommentService.selectFsCourseWatchCommentList(fsCourseWatchComment);
+        ExcelUtil<FsCourseWatchComment> util = new ExcelUtil<FsCourseWatchComment>(FsCourseWatchComment.class);
+        return util.exportExcel(list, "看课评论数据");
+    }
+
+    /**
+     * 获取看课评论详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:query')")
+    @GetMapping(value = "/{commentId}")
+    public AjaxResult getInfo(@PathVariable("commentId") Long commentId)
+    {
+        return AjaxResult.success(fsCourseWatchCommentService.selectFsCourseWatchCommentByCommentId(commentId));
+    }
+
+    /**
+     * 新增看课评论
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:add')")
+    @Log(title = "看课评论", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseWatchComment fsCourseWatchComment)
+    {
+        return toAjax(fsCourseWatchCommentService.insertFsCourseWatchComment(fsCourseWatchComment));
+    }
+
+    /**
+     * 修改看课评论
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:edit')")
+    @Log(title = "看课评论", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseWatchComment fsCourseWatchComment)
+    {
+        return toAjax(fsCourseWatchCommentService.updateFsCourseWatchComment(fsCourseWatchComment));
+    }
+
+    /**
+     * 删除看课评论
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:remove')")
+    @Log(title = "看课评论", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{commentIds}")
+    public AjaxResult remove(@PathVariable Long[] commentIds)
+    {
+        return toAjax(fsCourseWatchCommentService.deleteFsCourseWatchCommentByCommentIds(commentIds));
+    }
+}

+ 2 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -30,6 +30,8 @@ public class CourseConfig implements Serializable {
     private List<DisabledTimeVo> disabledTimeList;//充值手续费百分比
     private Integer completionMode; // 完课模式
     private Integer minutesNum; //多少分钟算完课
+    private Integer isOpenComment; //是否开启评论
+    private Integer viewCommentNum; // 查看历史评论数量
 
 
     @Data

+ 54 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseWatchComment.java

@@ -0,0 +1,54 @@
+package com.fs.course.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 看课评论对象 fs_course_watch_comment
+ *
+ * @author fs
+ * @date 2025-05-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseWatchComment extends BaseEntity{
+
+    /** 评论id */
+    private Long commentId;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户类型,1-管理员,2-用户 */
+    @Excel(name = "用户类型,1-管理员,2-用户")
+    private Integer userType;
+
+    /** 课程id */
+    @Excel(name = "课程id")
+    private Long courseId;
+
+    /** 视频id */
+    @Excel(name = "视频id")
+    private Long videoId;
+
+    /** 评论类型 1:评论,2:回复 */
+    @Excel(name = "评论类型 1:评论,2:回复")
+    private Integer type;
+
+    /** 父评论id */
+    @Excel(name = "父评论id")
+    private Long parentId;
+
+    /** 评论内容 */
+    @Excel(name = "评论内容")
+    private String content;
+
+    /** 是否是撤回的消息,1-是,0-否 */
+    @Excel(name = "是否是撤回的消息,1-是,0-否")
+    private Integer isRevoke;
+
+
+}

+ 80 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchCommentMapper.java

@@ -0,0 +1,80 @@
+package com.fs.course.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsCourseWatchComment;
+import com.fs.course.param.FsCourseWatchCommentListParam;
+import com.fs.course.vo.FsCourseWatchCommentVO;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 看课评论Mapper接口
+ *
+ * @author fs
+ * @date 2025-05-26
+ */
+public interface FsCourseWatchCommentMapper extends BaseMapper<FsCourseWatchComment>{
+    /**
+     * 查询看课评论
+     *
+     * @param commentId 看课评论主键
+     * @return 看课评论
+     */
+    FsCourseWatchComment selectFsCourseWatchCommentByCommentId(Long commentId);
+
+    /**
+     * 查询看课评论列表
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 看课评论集合
+     */
+    List<FsCourseWatchComment> selectFsCourseWatchCommentList(FsCourseWatchComment fsCourseWatchComment);
+
+    /**
+     * 新增看课评论
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 结果
+     */
+    int insertFsCourseWatchComment(FsCourseWatchComment fsCourseWatchComment);
+
+    /**
+     * 修改看课评论
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 结果
+     */
+    int updateFsCourseWatchComment(FsCourseWatchComment fsCourseWatchComment);
+
+    /**
+     * 删除看课评论
+     *
+     * @param commentId 看课评论主键
+     * @return 结果
+     */
+    int deleteFsCourseWatchCommentByCommentId(Long commentId);
+
+    /**
+     * 批量删除看课评论
+     *
+     * @param commentIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseWatchCommentByCommentIds(Long[] commentIds);
+
+    /**
+     * 撤销评论
+     * @param commentId 评论id
+     * @return int,1-是,0-否
+     */
+    @Update("update fs_course_watch_comment set is_revoke = 1 where comment_id = #{commentId}")
+    int revokeH5CourseWatchComment(Long commentId);
+
+    /**
+     * h5查询评论列表
+     * @param param 入参
+     * @return list
+     */
+    List<FsCourseWatchCommentVO> selectH5CourseWatchComments(FsCourseWatchCommentListParam param);
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseWatchCommentListParam.java

@@ -0,0 +1,20 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "评论列表查询参数")
+public class FsCourseWatchCommentListParam{
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum = 1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "不传,通过配置获取")
+    private Integer listNum;
+
+}

+ 32 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseWatchCommentSaveParam.java

@@ -0,0 +1,32 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 保存看课评论入参
+ */
+@Data
+@ApiModel(value = "保存看课评论入参")
+public class FsCourseWatchCommentSaveParam{
+
+    @ApiModelProperty(value = "用户id,不传")
+    private Long userId;
+
+    @ApiModelProperty(value = "用户类型,1-管理员,2-用户")
+    private Integer userType;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+    @ApiModelProperty(value = "视频id")
+    private Long videoId;
+
+    @ApiModelProperty(value = "评论类型 1:评论,2:回复,目前没有回复功能,默认传1就行了")
+    private Integer type;
+
+    @ApiModelProperty(value = "评论内容")
+    private String content;
+
+}

+ 87 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseWatchCommentService.java

@@ -0,0 +1,87 @@
+package com.fs.course.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.course.domain.FsCourseWatchComment;
+import com.fs.course.param.FsCourseWatchCommentListParam;
+import com.fs.course.param.FsCourseWatchCommentSaveParam;
+import com.fs.course.vo.FsCourseWatchCommentVO;
+
+/**
+ * 看课评论Service接口
+ *
+ * @author fs
+ * @date 2025-05-26
+ */
+public interface IFsCourseWatchCommentService extends IService<FsCourseWatchComment>{
+    /**
+     * 查询看课评论
+     *
+     * @param commentId 看课评论主键
+     * @return 看课评论
+     */
+    FsCourseWatchComment selectFsCourseWatchCommentByCommentId(Long commentId);
+
+    /**
+     * 查询看课评论列表
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 看课评论集合
+     */
+    List<FsCourseWatchComment> selectFsCourseWatchCommentList(FsCourseWatchComment fsCourseWatchComment);
+
+    /**
+     * 新增看课评论
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 结果
+     */
+    int insertFsCourseWatchComment(FsCourseWatchComment fsCourseWatchComment);
+
+    /**
+     * 修改看课评论
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 结果
+     */
+    int updateFsCourseWatchComment(FsCourseWatchComment fsCourseWatchComment);
+
+    /**
+     * 批量删除看课评论
+     *
+     * @param commentIds 需要删除的看课评论主键集合
+     * @return 结果
+     */
+    int deleteFsCourseWatchCommentByCommentIds(Long[] commentIds);
+
+    /**
+     * 删除看课评论信息
+     *
+     * @param commentId 看课评论主键
+     * @return 结果
+     */
+    int deleteFsCourseWatchCommentByCommentId(Long commentId);
+
+    /**
+     * 保存h5的评论数据
+     * @param param 入参
+     * @return
+     */
+    R saveH5CourseWatchComment(FsCourseWatchCommentSaveParam param);
+
+    /**
+     * 撤销评论
+     * @param commentId 评论id
+     * @return R
+     */
+    R revokeH5CourseWatchComment(Long commentId);
+
+    /**
+     * h5查询评论列表
+     * @param param 入参
+     * @return list
+     */
+    List<FsCourseWatchCommentVO> selectH5CourseWatchComments(FsCourseWatchCommentListParam param);
+
+}

+ 127 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchCommentServiceImpl.java

@@ -0,0 +1,127 @@
+package com.fs.course.service.impl;
+
+import java.util.List;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.param.FsCourseWatchCommentListParam;
+import com.fs.course.param.FsCourseWatchCommentSaveParam;
+import com.fs.course.vo.FsCourseWatchCommentVO;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import com.fs.course.mapper.FsCourseWatchCommentMapper;
+import com.fs.course.domain.FsCourseWatchComment;
+import com.fs.course.service.IFsCourseWatchCommentService;
+
+/**
+ * 看课评论Service业务层处理
+ *
+ * @author fs
+ * @date 2025-05-26
+ */
+@Service
+public class FsCourseWatchCommentServiceImpl extends ServiceImpl<FsCourseWatchCommentMapper, FsCourseWatchComment> implements IFsCourseWatchCommentService {
+
+    /**
+     * 查询看课评论
+     *
+     * @param commentId 看课评论主键
+     * @return 看课评论
+     */
+    @Override
+    public FsCourseWatchComment selectFsCourseWatchCommentByCommentId(Long commentId)
+    {
+        return baseMapper.selectFsCourseWatchCommentByCommentId(commentId);
+    }
+
+    /**
+     * 查询看课评论列表
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 看课评论
+     */
+    @Override
+    public List<FsCourseWatchComment> selectFsCourseWatchCommentList(FsCourseWatchComment fsCourseWatchComment)
+    {
+        return baseMapper.selectFsCourseWatchCommentList(fsCourseWatchComment);
+    }
+
+    /**
+     * 新增看课评论
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseWatchComment(FsCourseWatchComment fsCourseWatchComment)
+    {
+        fsCourseWatchComment.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsCourseWatchComment(fsCourseWatchComment);
+    }
+
+    /**
+     * 修改看课评论
+     *
+     * @param fsCourseWatchComment 看课评论
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseWatchComment(FsCourseWatchComment fsCourseWatchComment)
+    {
+        fsCourseWatchComment.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseWatchComment(fsCourseWatchComment);
+    }
+
+    /**
+     * 批量删除看课评论
+     *
+     * @param commentIds 需要删除的看课评论主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseWatchCommentByCommentIds(Long[] commentIds)
+    {
+        return baseMapper.deleteFsCourseWatchCommentByCommentIds(commentIds);
+    }
+
+    /**
+     * 删除看课评论信息
+     *
+     * @param commentId 看课评论主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseWatchCommentByCommentId(Long commentId)
+    {
+        return baseMapper.deleteFsCourseWatchCommentByCommentId(commentId);
+    }
+
+    @Override
+    public R saveH5CourseWatchComment(FsCourseWatchCommentSaveParam param) {
+        FsCourseWatchComment fsCourseWatchComment = new FsCourseWatchComment();
+        BeanUtils.copyProperties(param, fsCourseWatchComment);
+        fsCourseWatchComment.setCreateTime(DateUtils.getNowDate());
+        int i = baseMapper.insertFsCourseWatchComment(fsCourseWatchComment);
+        if (i > 0){
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
+
+    @Override
+    public R revokeH5CourseWatchComment(Long commentId) {
+        int i = baseMapper.revokeH5CourseWatchComment(commentId);
+        if (i > 0){
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
+
+    @Override
+    public List<FsCourseWatchCommentVO> selectH5CourseWatchComments(FsCourseWatchCommentListParam param) {
+        return baseMapper.selectH5CourseWatchComments(param);
+    }
+
+}

+ 38 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseWatchCommentVO.java

@@ -0,0 +1,38 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.Date;
+
+@Data
+@ApiModel(value = "看课评论列表")
+public class FsCourseWatchCommentVO{
+
+    @ApiModelProperty(value = "评论id")
+    private Long commentId;
+
+    @ApiModelProperty(value = "用户id")
+    private Long userId;
+
+    @ApiModelProperty(value = "用户类型,1-管理员,2-用户")
+    private Integer userType;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+    @ApiModelProperty(value = "视频id")
+    private Long videoId;
+
+    @ApiModelProperty(value = "评论类型")
+    private Integer type;
+
+    @ApiModelProperty(value = "评论内容")
+    private String content;
+
+    @ApiModelProperty(value = "创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+}

+ 108 - 0
fs-service/src/main/resources/mapper/course/FsCourseWatchCommentMapper.xml

@@ -0,0 +1,108 @@
+<?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="com.fs.course.mapper.FsCourseWatchCommentMapper">
+
+    <resultMap type="FsCourseWatchComment" id="FsCourseWatchCommentResult">
+        <result property="commentId"    column="comment_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="userType"    column="user_type"    />
+        <result property="courseId"    column="course_id"    />
+        <result property="videoId"    column="video_id"    />
+        <result property="type"    column="type"    />
+        <result property="parentId"    column="parent_id"    />
+        <result property="content"    column="content"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="isRevoke"    column="is_revoke"    />
+    </resultMap>
+
+    <sql id="selectFsCourseWatchCommentVo">
+        select comment_id, user_id, user_type, course_id, video_id, type, parent_id, content, create_time, update_time, is_revoke from fs_course_watch_comment
+    </sql>
+
+    <select id="selectFsCourseWatchCommentList" parameterType="FsCourseWatchComment" resultMap="FsCourseWatchCommentResult">
+        <include refid="selectFsCourseWatchCommentVo"/>
+        <where>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="userType != null "> and user_type = #{userType}</if>
+            <if test="courseId != null "> and course_id = #{courseId}</if>
+            <if test="videoId != null "> and video_id = #{videoId}</if>
+            <if test="type != null "> and type = #{type}</if>
+            <if test="parentId != null "> and parent_id = #{parentId}</if>
+            <if test="content != null  and content != ''"> and content = #{content}</if>
+            <if test="isRevoke != null "> and is_revoke = #{isRevoke}</if>
+        </where>
+    </select>
+
+    <select id="selectFsCourseWatchCommentByCommentId" parameterType="Long" resultMap="FsCourseWatchCommentResult">
+        <include refid="selectFsCourseWatchCommentVo"/>
+        where comment_id = #{commentId}
+    </select>
+
+    <insert id="insertFsCourseWatchComment" parameterType="FsCourseWatchComment" useGeneratedKeys="true" keyProperty="commentId">
+        insert into fs_course_watch_comment
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="userType != null">user_type,</if>
+            <if test="courseId != null">course_id,</if>
+            <if test="videoId != null">video_id,</if>
+            <if test="type != null">type,</if>
+            <if test="parentId != null">parent_id,</if>
+            <if test="content != null">content,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="isRevoke != null">is_revoke,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="userType != null">#{userType},</if>
+            <if test="courseId != null">#{courseId},</if>
+            <if test="videoId != null">#{videoId},</if>
+            <if test="type != null">#{type},</if>
+            <if test="parentId != null">#{parentId},</if>
+            <if test="content != null">#{content},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="isRevoke != null">#{isRevoke},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseWatchComment" parameterType="FsCourseWatchComment">
+        update fs_course_watch_comment
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="userType != null">user_type = #{userType},</if>
+            <if test="courseId != null">course_id = #{courseId},</if>
+            <if test="videoId != null">video_id = #{videoId},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="parentId != null">parent_id = #{parentId},</if>
+            <if test="content != null">content = #{content},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="isRevoke != null">is_revoke = #{isRevoke},</if>
+        </trim>
+        where comment_id = #{commentId}
+    </update>
+
+    <delete id="deleteFsCourseWatchCommentByCommentId" parameterType="Long">
+        delete from fs_course_watch_comment where comment_id = #{commentId}
+    </delete>
+
+    <delete id="deleteFsCourseWatchCommentByCommentIds" parameterType="String">
+        delete from fs_course_watch_comment where comment_id in
+        <foreach item="commentId" collection="array" open="(" separator="," close=")">
+            #{commentId}
+        </foreach>
+    </delete>
+
+    <select id="selectH5CourseWatchComments" resultType="com.fs.course.vo.FsCourseWatchCommentVO">
+        select comment_id, user_id, user_type, course_id, video_id, type, content, create_time from fs_course_watch_comment
+        <where>
+           and is_revoke = 0
+        </where>
+        order by create_time desc
+    </select>
+
+</mapper>

+ 4 - 1
fs-user-app/pom.xml

@@ -15,7 +15,10 @@
     </description>
 
     <dependencies>
-
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
         <!-- spring-boot-devtools -->
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 42 - 0
fs-user-app/src/main/java/com/fs/app/config/WebSocketConfig.java

@@ -0,0 +1,42 @@
+package com.fs.app.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
+
+@Configuration
+public class WebSocketConfig {
+    /**
+     * 自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
+     *
+     * @return
+     */
+
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
+
+    /**
+     * 通信文本消息和二进制缓存区大小
+     * 避免对接 第三方 报文过大时,Websocket 1009 错误
+     *
+     * @return
+     */
+
+    @Bean
+    public ServletServerContainerFactoryBean createWebSocketContainer() {
+        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
+        // 设置文本消息缓冲区大小
+        container.setMaxTextMessageBufferSize(10240000);
+        // 设置二进制消息缓冲区大小
+        container.setMaxBinaryMessageBufferSize(10240000);
+        // 设置最大会话空闲超时时间(单位:毫秒)
+        container.setMaxSessionIdleTimeout(20 * 60000L); // 15分钟
+        // 设置异步发送超时时间(单位:毫秒)
+        container.setAsyncSendTimeout(300 * 1000L);
+        return container;
+    }
+
+}

+ 46 - 14
fs-user-app/src/main/java/com/fs/app/controller/CourseH5Controller.java

@@ -3,37 +3,26 @@ package com.fs.app.controller;
 
 import cn.hutool.json.JSONUtil;
 import com.fs.app.annotation.Login;
-import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
-import com.fs.common.utils.DateUtils;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
-import com.fs.core.utils.OrderCodeUtils;
+import com.fs.common.core.domain.ResponseResult;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.param.*;
 import com.fs.course.service.*;
-import com.fs.course.service.impl.TencentCloudCosService;
 import com.fs.course.vo.*;
-import com.fs.his.vo.OptionsVO;
 import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import io.jsonwebtoken.Claims;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import lombok.Synchronized;
+import io.swagger.annotations.ApiParam;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
-import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.*;
+import java.util.List;
 
 @Api("h5课堂接口")
 @RestController
@@ -54,6 +43,9 @@ public class CourseH5Controller extends  AppBaseController{
     @Autowired
     private IFsCourseWatchLogService courseWatchLogService;
 
+    @Autowired
+    private IFsCourseWatchCommentService courseWatchCommentService;
+
 
     @ApiOperation("h5课程简介")
     @GetMapping("/getH5CourseByVideoId")
@@ -135,4 +127,44 @@ public class CourseH5Controller extends  AppBaseController{
         logger.error("zyp \n【h5看课中途报错】:{}",msg);
     }
 
+    @Login
+    @ApiOperation("保存评论数据")
+    @PostMapping("/saveMsg")
+    public R saveMsg(@RequestBody FsCourseWatchCommentSaveParam param)
+    {
+//        param.setUserId(Long.parseLong(getUserId()));
+        return courseWatchCommentService.saveH5CourseWatchComment(param);
+    }
+
+    @Login
+    @ApiOperation("撤销评论")
+    @PutMapping("/revokeMsg")
+    public R revokeMsg(@ApiParam(value = "评论id", required = true) @RequestParam Long commentId)
+    {
+        return courseWatchCommentService.revokeH5CourseWatchComment(commentId);
+    }
+
+    @ApiOperation("获取历史评论数据")
+    @GetMapping("/getComments")
+    public ResponseResult<PageInfo<FsCourseWatchCommentVO>> getCourseWatchComments(@ApiParam(value = "页码", required = true) @RequestParam Integer pageNum,
+                                                 @ApiParam(value = "每页大小", required = true) @RequestParam Integer pageSize)
+    {
+        //获取配置信息中需要查询的数据条数
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        FsCourseWatchCommentListParam param = new FsCourseWatchCommentListParam();
+        param.setPageNum(pageNum);
+        param.setPageSize(pageSize);
+        param.setListNum(config.getViewCommentNum() != null &&  config.getViewCommentNum() != 0 ? config.getViewCommentNum() : 200);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsCourseWatchCommentVO> list = courseWatchCommentService.selectH5CourseWatchComments(param);
+        PageInfo<FsCourseWatchCommentVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+
+
+
 }

+ 36 - 0
fs-user-app/src/main/java/com/fs/websocket/bean/SendMsgVO.java

@@ -0,0 +1,36 @@
+package com.fs.websocket.bean;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+//@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class SendMsgVO {
+
+    @ApiModelProperty("用户id")
+    private Long userId;
+
+    @ApiModelProperty("用户类型,1-管理员,2-用户")
+    private Integer userType;
+
+    @ApiModelProperty("课程id")
+    private Long courseId;
+
+    @ApiModelProperty("视频id")
+    private Long videoId;
+
+    @ApiModelProperty("评论类型 1:评论,2:回复")
+    private Integer type;
+
+    @ApiModelProperty("消息代码,heartbeat-检测心跳;sendMsg-发送消息")
+    private String cmd;
+
+    @ApiModelProperty("消息内容")
+    private String msg;
+
+
+}

+ 108 - 0
fs-user-app/src/main/java/com/fs/websocket/service/WebSocketServer.java

@@ -0,0 +1,108 @@
+package com.fs.websocket.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.StringUtils;
+import com.fs.websocket.bean.SendMsgVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import javax.websocket.*;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+@ServerEndpoint("/app/webSocket/{userId}")
+@Component
+@Slf4j
+public class WebSocketServer {
+
+    //concurrent包的线程安全,用来存放每个客户端对应的WebSocketServer的会话对象
+    private static final ConcurrentHashMap<Long, Session> sessionPools = new ConcurrentHashMap<>();
+//    private final RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
+
+    //分发消息
+    public void sendMessageToAll(String message) throws IOException {
+        Collection<Session> sessions = sessionPools.values();
+        if(!CollectionUtils.isEmpty(sessions)){
+            for (Session session : sessions) {
+                System.out.println("发送数据:" + message);
+                session.getBasicRemote().sendText(message);
+                log.info("分发消息结束,人数,{},消息内容,{}",  sessionPools.size(), message);
+            }
+        }
+    }
+
+    //指定用户发送消息
+    public static void sendMessage(Session session, String message) throws IOException {
+        if(session != null){
+            synchronized (session) {
+                log.info("发送数据:{}", message);
+                session.getBasicRemote().sendText(message);
+            }
+        }
+    }
+
+    //建立连接成功调用
+    @OnOpen
+    public void onOpen(Session session,  @PathParam(value = "userId") Long userId) {
+        Map<String, String> params = getParams(session);
+        if(userId == null || !params.containsKey("userId")){
+            throw new BaseException("用户信息错误");
+        }
+        sessionPools.put(userId, session);
+        System.out.println("已成功加入webSocket连接!当前人数为,"+ sessionPools.size());
+        log.info("{}已成功加入webSocket连接!当前人数为,{}", userId, sessionPools.size());
+    }
+
+
+    //收到客户端信息
+    @OnMessage
+    public void onMessage(String message) throws IOException {
+        SendMsgVO msg = JSONObject.parseObject(message, SendMsgVO.class);
+        Session session;
+        try {
+            switch (msg.getCmd()) {
+                case "heartbeat":
+                    session = sessionPools.get(msg.getUserId());
+                    sendMessage(session, JSONObject.toJSONString(msg));
+                    break;
+                case "sendMsg":
+                    // 分发消息
+                    sendMessageToAll(JSONObject.toJSONString(R.ok().put("data", msg)));
+                    break;
+            }
+        } catch (Exception e) {
+            log.error("webSocket消息发送错误,{}", e.getMessage());
+        }
+
+    }
+
+    //关闭连接时调用
+    @OnClose
+    public void onClose(Session session) {
+        Map<String, String> params = getParams(session);
+        long userId = Long.parseLong(params.get("userId"));
+        sessionPools.remove(userId);
+        log.info("{}已断开webSocket连接!当前人数为,{}", userId, sessionPools.size());
+    }
+
+    //错误时调用
+    @OnError
+    public void onError(Session session, Throwable throwable) {
+        log.error("webSocket连接错误,{}", throwable.getMessage());
+        throwable.printStackTrace();
+    }
+
+    private Map<String, String> getParams(Session session){
+        return session.getRequestParameterMap().entrySet().stream()
+                .filter(e -> e.getValue() != null && !e.getValue().isEmpty() && StringUtils.isNotEmpty(e.getValue().get(0)))
+                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
+    }
+}