فهرست منبع

Merge branch 'refs/heads/master_fix_auto_tag_20251105'

xdd 1 هفته پیش
والد
کامیت
3e0e693cfd

+ 37 - 0
fs-admin/src/test/java/com/fs/api/controller/IndexStatisticsControllerTest.java

@@ -0,0 +1,37 @@
+package com.fs.api.controller;
+
+import com.fs.FSApplication;
+import com.fs.common.core.domain.R;
+import com.fs.statis.dto.AnalysisPreviewQueryDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = FSApplication.class)
+@RequiredArgsConstructor
+@Slf4j
+public class IndexStatisticsControllerTest {
+
+    @Autowired
+    private IndexStatisticsController indexStatisticsController;
+
+    @Test
+    public void analysisPreview() {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setCompanyId(null);
+        dto.setDeptId(1L);
+        dto.setEndTime("2025-10-31 23:59:59");
+        dto.setStartTime("2025-10-01 00:00:00");
+        dto.setType(4);
+        dto.setUserType(1);
+        R r = indexStatisticsController.analysisPreview(dto);
+        log.info("r: {}",r);
+    }
+}

+ 104 - 0
fs-company/src/main/java/com/fs/company/controller/tag/FsVideoCourseTagController.java

@@ -0,0 +1,104 @@
+package com.fs.company.controller.tag;
+
+import java.util.List;
+
+import com.fs.tag.domain.FsVideoCourseTag;
+import com.fs.tag.service.IFsVideoCourseTagService;
+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.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 视频小节看课标签关联Controller
+ *
+ * @author fs
+ * @date 2025-11-05
+ */
+@RestController
+@RequestMapping("/shop/tag")
+public class FsVideoCourseTagController extends BaseController
+{
+    @Autowired
+    private IFsVideoCourseTagService fsVideoCourseTagService;
+
+    /**
+     * 查询视频小节看课标签关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:tag:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsVideoCourseTag fsVideoCourseTag)
+    {
+        startPage();
+        List<FsVideoCourseTag> list = fsVideoCourseTagService.selectFsVideoCourseTagList(fsVideoCourseTag);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出视频小节看课标签关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:tag:export')")
+    @Log(title = "视频小节看课标签关联", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsVideoCourseTag fsVideoCourseTag)
+    {
+        List<FsVideoCourseTag> list = fsVideoCourseTagService.selectFsVideoCourseTagList(fsVideoCourseTag);
+        ExcelUtil<FsVideoCourseTag> util = new ExcelUtil<FsVideoCourseTag>(FsVideoCourseTag.class);
+        return util.exportExcel(list, "视频小节看课标签关联数据");
+    }
+
+    /**
+     * 获取视频小节看课标签关联详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('shop:tag:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsVideoCourseTagService.selectFsVideoCourseTagById(id));
+    }
+
+    /**
+     * 新增视频小节看课标签关联
+     */
+    @PreAuthorize("@ss.hasPermi('shop:tag:add')")
+    @Log(title = "视频小节看课标签关联", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsVideoCourseTag fsVideoCourseTag)
+    {
+        return toAjax(fsVideoCourseTagService.insertFsVideoCourseTag(fsVideoCourseTag));
+    }
+
+    /**
+     * 修改视频小节看课标签关联
+     */
+    @PreAuthorize("@ss.hasPermi('shop:tag:edit')")
+    @Log(title = "视频小节看课标签关联", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsVideoCourseTag fsVideoCourseTag)
+    {
+        return toAjax(fsVideoCourseTagService.updateFsVideoCourseTag(fsVideoCourseTag));
+    }
+
+    /**
+     * 删除视频小节看课标签关联
+     */
+    @PreAuthorize("@ss.hasPermi('shop:tag:remove')")
+    @Log(title = "视频小节看课标签关联", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsVideoCourseTagService.deleteFsVideoCourseTagByIds(ids));
+    }
+}

+ 2 - 2
fs-ipad-task/src/test/java/com/fs/app/task/SendMsgTest.java

@@ -37,11 +37,11 @@ public class SendMsgTest {
 
     @Test
     public void testLogWrite(){
-        List<Long> testLogIds = Arrays.asList(177L,180L,182L,183L,184L,185L);
+        List<Long> testLogIds = Arrays.asList(194L,195L);
 
         for(Long logId : testLogIds){
             FsCourseWatchLog fsCourseWatchLog = fsCourseWatchLogMapper.selectFsCourseWatchLogByLogId(logId);
-            fsTagUpdateService.onCourseWatchingBatch(Collections.singletonList(fsCourseWatchLog));
+            fsTagUpdateService.onCourseWatchFinishedBatch(Collections.singletonList(fsCourseWatchLog));
         }
     }
 

+ 0 - 27
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -112,31 +112,4 @@ public class FsUserCourseVideo extends BaseEntity
 
     private Long listingEndTime;//商品结束售卖时间
 
-
-    /**
-     * 看课中标签ID
-     */
-    private String watchingTagId;
-    /**
-     * 完课标签ID
-     */
-    private String watchedTagId;
-    /**
-     * 标签组ID
-     */
-    private String tagGroupId;
-
-    /**
-     * 标签组表中的ID
-     */
-    private Long tgId;
-    /**
-     * 看课标签 表中的ID
-     */
-    private Long watchingTgId;
-    /**
-     * 完课标签 表中的ID
-     */
-    private Long watchedTgId;
-
 }

+ 1 - 24
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -942,30 +942,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     @Override
     public List<FsUserCourseVideoVO> selectFsUserCourseVideoListByCourseIdAndCompany(FsUserCourseVideoParam fsUserCourseVideo) {
-        List<FsUserCourseVideoVO> fsUserCourseVideoVOS = fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseIdAndCompany(fsUserCourseVideo);
-        for (FsUserCourseVideoVO item : fsUserCourseVideoVOS) {
-            if(ObjectUtils.isNotNull(item.getTgId())){
-                QwTagGroup qwTagGroup = qwTagGroupMapper.selectQwTagGroupById(item.getTgId());
-                if(ObjectUtils.isNotNull(qwTagGroup)){
-                    item.setTagGroupName(qwTagGroup.getName());
-                }
-            }
-
-            if(ObjectUtils.isNotNull(item.getWatchingTgId())){
-                QwTag qwTag = qwTagMapper.selectQwTagById(item.getWatchingTgId());
-                if(ObjectUtils.isNotNull(qwTag)){
-                    item.setWatchingTagName(qwTag.getName());
-                }
-            }
-
-            if(ObjectUtils.isNotNull(item.getWatchedTgId())) {
-                QwTag qwTag = qwTagMapper.selectQwTagById(item.getWatchedTgId());
-                if(ObjectUtils.isNotNull(qwTag)){
-                    item.setWatchedTagName(qwTag.getName());
-                }
-            }
-        }
-        return fsUserCourseVideoVOS;
+        return fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseIdAndCompany(fsUserCourseVideo);
     }
 
     @Override

+ 0 - 39
fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoVO.java

@@ -68,43 +68,4 @@ public class FsUserCourseVideoVO extends BaseEntity {
     private String redPacketMoney;
 
     private String companyRedPacketMoney;
-    /**
-     * 标签组表中的ID
-     */
-    private Long tgId;
-    /**
-     * 看课标签 表中的ID
-     */
-    private Long watchingTgId;
-    /**
-     * 完课标签 表中的ID
-     */
-    private Long watchedTgId;
-
-    /**
-     * 看课中标签ID
-     */
-    private String watchingTagId;
-    /**
-     * 完课标签ID
-     */
-    private String watchedTagId;
-    /**
-     * 标签组ID
-     */
-    private String tagGroupId;
-
-    /**
-     * 标签组名称
-     */
-    private String tagGroupName;
-    /**
-     * 看课标签
-     */
-    private String watchingTagName;
-    /**
-     * 完课标签
-     */
-    private String watchedTagName;
-
 }

+ 16 - 10
fs-service/src/main/java/com/fs/tag/domain/FsTagUpdateQueue.java

@@ -1,5 +1,6 @@
 package com.fs.tag.domain;
 
+import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.time.LocalDateTime;
@@ -27,11 +28,6 @@ public class FsTagUpdateQueue {
     /** 课程ID */
     private Long courseId;
 
-    /** 标签id */
-    private String tagId;
-
-    /** 标签名称 */
-    private String tagName;
 
     /** 操作类型(0 ADD 1 REMOVE) 默认0 */
     private Integer operationType;
@@ -96,18 +92,28 @@ public class FsTagUpdateQueue {
      */
     private String watchedTagId;
     /**
-     * 标签组ID
+     * 看课标签组ID
      */
-    private String tagGroupId;
+    private String watchingTgGroupId;
 
     /**
-     * 标签组表中的ID
+     * 完课标签组ID
      */
-    private Long tgId;
+    private String watchedTgGroupId;
+    /** 看课中-标签组ID */
+    private Long watchingGroupId;
+
     /**
-     * 看课标签 表中的ID
+     * 完课标签组-标签组表中的ID
+     */
+    private Long watchedTagGroupId;
+    /**
+     * 看课中标签-表中的ID
      */
     private Long watchingTgId;
+
+    /** 完课-标签组ID */
+    private Long watchedGroupId;
     /**
      * 完课标签 表中的ID
      */

+ 96 - 0
fs-service/src/main/java/com/fs/tag/domain/FsVideoCourseTag.java

@@ -0,0 +1,96 @@
+package com.fs.tag.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 视频小节看课标签关联对象 fs_video_course_tag
+ *
+ * @author fs
+ * @date 2025-11-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsVideoCourseTag extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 企微公司 */
+    @Excel(name = "企微公司")
+    private String corpId;
+    /**
+     * 企微公司名
+     */
+    private String qwCompanyName;
+    /** 视频ID */
+    @Excel(name = "视频ID")
+    private Long videoId;
+    /**
+     * 小节名称
+     */
+    private String videoName;
+
+    /** 看课中-标签组ID */
+    @Excel(name = "看课中-标签组ID")
+    private Long watchingGroupId;
+    /**
+     * 看课中-标签组名
+     */
+    private String watchingGroupName;
+
+    /** 完课-标签组ID */
+    @Excel(name = "完课-标签组ID")
+    private Long watchedGroupId;
+    /**
+     * 完课-标签组名
+     */
+    private String watchedGroupName;
+
+    /** 看课中-标签组ID */
+    @Excel(name = "看课中-标签组ID")
+    private Long watchingTgId;
+    /**
+     * 看课中标签名
+     */
+    private String watchingTgName;
+
+    /** 完课-标签组ID */
+    @Excel(name = "完课-标签组ID")
+    private Long watchedTgId;
+
+    /**
+     * 完课-标签名
+     */
+    private String watchedTgName;
+
+    /** 看课中-标签组ID */
+    @Excel(name = "看课中-标签组ID")
+    private String watchingGroupTgId;
+
+
+    /** 完课-标签组ID */
+    @Excel(name = "完课-标签组ID")
+    private String watchedGroupTgId;
+
+
+    /** 看课中-标签ID */
+    @Excel(name = "看课中-标签ID")
+    private String watchingTagId;
+
+    /** 完课-标签组 */
+    @Excel(name = "完课-标签组")
+    private String watchedTagId;
+
+
+    /**
+     * corp_id, '_', video_id
+     */
+    @TableField(exist = false)
+    private String compositeKey;
+
+}

+ 5 - 104
fs-service/src/main/java/com/fs/tag/mapper/FsTagUpdateQueueMapper.java

@@ -11,123 +11,26 @@ import java.util.List;
 @Mapper
 public interface FsTagUpdateQueueMapper {
 
-    @Select("select * from fs_tag_update_queue where retry_count < 3 and status in (0,3) and (next_execute_time < now() or next_execute_time is null) limit 500")
+    @Select("select * from fs_tag_update_queue where retry_count < 3 and status in (0,3) and (next_execute_time < now() or next_execute_time is null) limit 1000")
     List<FsTagUpdateQueue> selectPending();
 
-    @Select("<script>" +
-            "SELECT * FROM fs_tag_update_queue " +
-            "<where>" +
-            "<if test='id != null'> AND id = #{id} </if>" +
-            "<if test='courseLogId != null'> AND course_log_id = #{courseLogId} </if>" +
-            "<if test='courseId != null'> AND course_id = #{courseId} </if>" +
-            "<if test='tagId != null'> AND tag_id = #{tagId} </if>" +
-            "<if test='tagName != null'> AND tag_name = #{tagName} </if>" +
-            "<if test='operationType != null'> AND operation_type = #{operationType} </if>" +
-            "<if test='videoId != null'> AND video_id = #{videoId} </if>" +
-            "<if test='status != null'> AND status = #{status} </if>" +
-            "<if test='retryCount != null'> AND retry_count = #{retryCount} </if>" +
-            "<if test='corpId != null'> AND corp_id = #{corpId} </if>" +
-            "<if test='qwUserId != null'> AND qw_user_id = #{qwUserId} </if>" +
-            "</where>" +
-            "</script>")
-    List<FsTagUpdateQueue> selectByConditions(FsTagUpdateQueue condition);
-
-    @Insert("<script>" +
-            "INSERT INTO fs_tag_update_queue " +
-            "(course_log_id, course_id, tag_id, tag_name, operation_type, video_id, status, retry_count, corp_id, qw_user_id, fail_msg, payload, response, create_time, update_time, update_by, create_by,log_type) " +
-            "VALUES " +
-            "<trim prefix='(' suffix=')' suffixOverrides=','>" +
-            "<if test='courseLogId != null'>course_log_id,</if>" +
-            "<if test='courseId != null'>course_id,</if>" +
-            "<if test='tagId != null'>tag_id,</if>" +
-            "<if test='tagName != null'>tag_name,</if>" +
-            "<if test='operationType != null'>operation_type,</if>" +
-            "<if test='videoId != null'>video_id,</if>" +
-            "<if test='status != null'>status,</if>" +
-            "<if test='retryCount != null'>retry_count,</if>" +
-            "<if test='corpId != null'>corp_id,</if>" +
-            "<if test='qwUserId != null'>qw_user_id,</if>" +
-            "<if test='qwExternalContactId != null'>qw_external_contact_id,</if>" +
-            "<if test='failMsg != null'>fail_msg,</if>" +
-            "<if test='payload != null'>payload,</if>" +
-            "<if test='response != null'>response,</if>" +
-            "<if test='createTime != null'>create_time,</if>" +
-            "<if test='updateTime != null'>update_time,</if>" +
-            "<if test='updateBy != null'>update_by,</if>" +
-            "<if test='createBy != null'>create_by,</if>" +
-            "<if test='logType != null'>log_type,</if>" +
-            "</trim>" +
-            "<trim prefix='VALUES (' suffix=')' suffixOverrides=','>" +
-            "<if test='courseLogId != null'>#{courseLogId},</if>" +
-            "<if test='courseId != null'>#{courseId},</if>" +
-            "<if test='tagId != null'>#{tagId},</if>" +
-            "<if test='tagName != null'>#{tagName},</if>" +
-            "<if test='operationType != null'>#{operationType},</if>" +
-            "<if test='videoId != null'>#{videoId},</if>" +
-            "<if test='status != null'>#{status},</if>" +
-            "<if test='retryCount != null'>#{retryCount},</if>" +
-            "<if test='corpId != null'>#{corpId},</if>" +
-            "<if test='qwExternalContactId != null'>#{qwExternalContactId},</if>" +
-            "<if test='qwUserId != null'>#{qwUserId},</if>" +
-            "<if test='failMsg != null'>#{failMsg},</if>" +
-            "<if test='payload != null'>#{payload},</if>" +
-            "<if test='response != null'>#{response},</if>" +
-            "<if test='createTime != null'>#{createTime},</if>" +
-            "<if test='updateTime != null'>#{updateTime},</if>" +
-            "<if test='updateBy != null'>#{updateBy},</if>" +
-            "<if test='createBy != null'>#{createBy},</if>" +
-            "<if test='log_type != null'>#{logType},</if>" +
-            "</trim>" +
-            "</script>")
-    @Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")
-    int insertSelective(FsTagUpdateQueue record);
-
-
 
     @Insert("<script>" +
             "INSERT IGNORE INTO fs_tag_update_queue (" +
-            "course_log_id, is_first, course_id, tag_id, tag_name, operation_type, video_id, status, retry_count, " +
-            "corp_id, qw_user_id, qw_external_contact_id, fail_msg, payload, response, create_time, update_time, update_by, create_by, log_type,tg_id,watching_tg_id,watched_tg_id,watching_tag_id,watched_tag_id,tag_group_id" +
+            "course_log_id, is_first, course_id,  operation_type, video_id, status, retry_count, " +
+            "corp_id, qw_user_id, qw_external_contact_id, fail_msg, payload, response, create_time, update_time, update_by, create_by, log_type,watching_tg_id,watched_tg_id,watching_tag_id,watched_tag_id,watching_tg_group_id,watched_tg_group_id" +
             ") VALUES " +
             "<foreach collection='list' item='item' separator=','>" +
             "(" +
-            "#{item.courseLogId}, #{item.isFirst}, #{item.courseId}, #{item.tagId}, #{item.tagName}, #{item.operationType}, #{item.videoId}, #{item.status}, #{item.retryCount}, " +
+            "#{item.courseLogId}, #{item.isFirst}, #{item.courseId},  #{item.operationType}, #{item.videoId}, #{item.status}, #{item.retryCount}, " +
             "#{item.corpId}, #{item.qwUserId}, #{item.qwExternalContactId}, #{item.failMsg}, #{item.payload}, #{item.response}, #{item.createTime}," +
-            " #{item.updateTime}, #{item.updateBy}, #{item.createBy}, #{item.logType},#{item.tgId},#{item.watchingTgId},#{item.watchedTgId},#{item.watchingTagId},#{item.watchedTagId},#{item.tagGroupId}" +
+            " #{item.updateTime}, #{item.updateBy}, #{item.createBy}, #{item.logType},#{item.watchingTgId},#{item.watchedTgId},#{item.watchingTagId},#{item.watchedTagId},#{item.watchingTgGroupId},#{item.watchedTgGroupId}" +
             ")" +
             "</foreach>" +
             "</script>")
     int batchInsert(@Param("list") List<FsTagUpdateQueue> list);
 
 
-    @Update("<script>" +
-            "UPDATE fs_tag_update_queue " +
-            "<set>" +
-            "<if test='courseLogId != null'>course_log_id = #{courseLogId},</if>" +
-            "<if test='courseId != null'>course_id = #{courseId},</if>" +
-            "<if test='tagId != null'>tag_id = #{tagId},</if>" +
-            "<if test='tagName != null'>tag_name = #{tagName},</if>" +
-            "<if test='operationType != null'>operation_type = #{operationType},</if>" +
-            "<if test='videoId != null'>video_id = #{videoId},</if>" +
-            "<if test='status != null'>status = #{status},</if>" +
-            "<if test='retryCount != null'>retry_count = #{retryCount},</if>" +
-            "<if test='corpId != null'>corp_id = #{corpId},</if>" +
-            "<if test='qwUserId != null'>qw_user_id = #{qwUserId},</if>" +
-            "<if test='failMsg != null'>fail_msg = #{failMsg},</if>" +
-            "<if test='payload != null'>payload = #{payload},</if>" +
-            "<if test='response != null'>response = #{response},</if>" +
-            "<if test='createTime != null'>create_time = #{createTime},</if>" +
-            "<if test='updateTime != null'>update_time = #{updateTime},</if>" +
-            "<if test='updateBy != null'>update_by = #{updateBy},</if>" +
-            "<if test='createBy != null'>create_by = #{createBy},</if>" +
-            "<if test='logType != null'>log_type = #{logType},</if>" +
-            "</set> " +
-            "WHERE id = #{id}" +
-            "</script>")
-    int updateSelective(FsTagUpdateQueue record);
-
-
-
     @Update("<script>" +
             "<foreach collection='list' item='item' separator=';'>" +
             "UPDATE fs_tag_update_queue" +
@@ -135,8 +38,6 @@ public interface FsTagUpdateQueueMapper {
             "<if test='item.courseLogId != null'>course_log_id = #{item.courseLogId},</if>" +
             "<if test='item.isFirst != null'>is_first = #{item.isFirst},</if>" +
             "<if test='item.courseId != null'>course_id = #{item.courseId},</if>" +
-            "<if test='item.tagId != null'>tag_id = #{item.tagId},</if>" +
-            "<if test='item.tagName != null'>tag_name = #{item.tagName},</if>" +
             "<if test='item.operationType != null'>operation_type = #{item.operationType},</if>" +
             "<if test='item.videoId != null'>video_id = #{item.videoId},</if>" +
             "<if test='item.status != null'>status = #{item.status},</if>" +

+ 73 - 0
fs-service/src/main/java/com/fs/tag/mapper/FsVideoCourseTagMapper.java

@@ -0,0 +1,73 @@
+package com.fs.tag.mapper;
+
+import java.util.List;
+import java.util.Map;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.tag.domain.FsVideoCourseTag;
+import org.apache.ibatis.annotations.MapKey;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * 视频小节看课标签关联Mapper接口
+ *
+ * @author fs
+ * @date 2025-11-05
+ */
+public interface FsVideoCourseTagMapper extends BaseMapper<FsVideoCourseTag>{
+    /**
+     * 查询视频小节看课标签关联
+     *
+     * @param id 视频小节看课标签关联主键
+     * @return 视频小节看课标签关联
+     */
+    FsVideoCourseTag selectFsVideoCourseTagById(Long id);
+
+    /**
+     * 查询视频小节看课标签关联列表
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 视频小节看课标签关联集合
+     */
+    List<FsVideoCourseTag> selectFsVideoCourseTagList(FsVideoCourseTag fsVideoCourseTag);
+
+    /**
+     * 新增视频小节看课标签关联
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 结果
+     */
+    int insertFsVideoCourseTag(FsVideoCourseTag fsVideoCourseTag);
+
+    /**
+     * 修改视频小节看课标签关联
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 结果
+     */
+    int updateFsVideoCourseTag(FsVideoCourseTag fsVideoCourseTag);
+
+    /**
+     * 删除视频小节看课标签关联
+     *
+     * @param id 视频小节看课标签关联主键
+     * @return 结果
+     */
+    int deleteFsVideoCourseTagById(Long id);
+
+    /**
+     * 批量删除视频小节看课标签关联
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsVideoCourseTagByIds(Long[] ids);
+
+    @Select("select * from fs_video_course_tag where corp_id=#{corpId} and video_id=#{videoId}")
+    FsVideoCourseTag selectFsVideoCourseTagByCorpIdAndVideoId(@Param("corpId") String corpId, @Param("videoId") Long videoId);
+
+    @Select("SELECT id,corp_id,video_id,watching_group_id,watched_group_id,watching_tg_id,watched_tg_id,watching_group_tag_id as watching_group_tg_id,watched_group_tag_id as watched_group_tg_id,watching_tag_id,watched_tag_id, CONCAT(corp_id, '_', video_id) AS composite_key FROM fs_video_course_tag")
+    @MapKey("compositeKey")
+    Map<String,FsVideoCourseTag> selectAll();
+}

+ 61 - 0
fs-service/src/main/java/com/fs/tag/service/IFsVideoCourseTagService.java

@@ -0,0 +1,61 @@
+package com.fs.tag.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.tag.domain.FsVideoCourseTag;
+
+/**
+ * 视频小节看课标签关联Service接口
+ *
+ * @author fs
+ * @date 2025-11-05
+ */
+public interface IFsVideoCourseTagService extends IService<FsVideoCourseTag>{
+    /**
+     * 查询视频小节看课标签关联
+     *
+     * @param id 视频小节看课标签关联主键
+     * @return 视频小节看课标签关联
+     */
+    FsVideoCourseTag selectFsVideoCourseTagById(Long id);
+
+    /**
+     * 查询视频小节看课标签关联列表
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 视频小节看课标签关联集合
+     */
+    List<FsVideoCourseTag> selectFsVideoCourseTagList(FsVideoCourseTag fsVideoCourseTag);
+
+    /**
+     * 新增视频小节看课标签关联
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 结果
+     */
+    int insertFsVideoCourseTag(FsVideoCourseTag fsVideoCourseTag);
+
+    /**
+     * 修改视频小节看课标签关联
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 结果
+     */
+    int updateFsVideoCourseTag(FsVideoCourseTag fsVideoCourseTag);
+
+    /**
+     * 批量删除视频小节看课标签关联
+     *
+     * @param ids 需要删除的视频小节看课标签关联主键集合
+     * @return 结果
+     */
+    int deleteFsVideoCourseTagByIds(Long[] ids);
+
+    /**
+     * 删除视频小节看课标签关联信息
+     *
+     * @param id 视频小节看课标签关联主键
+     * @return 结果
+     */
+    int deleteFsVideoCourseTagById(Long id);
+}

+ 71 - 40
fs-service/src/main/java/com/fs/tag/service/impl/FsTagUpdateServiceImpl.java

@@ -2,6 +2,7 @@ package com.fs.tag.service.impl;
 
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.FsCourseWatchLog;
@@ -28,7 +29,9 @@ import com.fs.qwApi.param.QwAddTagParam;
 import com.fs.qwApi.param.QwEditUserTagParam;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.tag.domain.FsTagUpdateQueue;
+import com.fs.tag.domain.FsVideoCourseTag;
 import com.fs.tag.mapper.FsTagUpdateQueueMapper;
+import com.fs.tag.mapper.FsVideoCourseTagMapper;
 import com.fs.tag.service.FsTagUpdateService;
 import com.google.common.util.concurrent.RateLimiter;
 import lombok.extern.slf4j.Slf4j;
@@ -65,17 +68,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
     private QwApiService qwApiService;
 
     @Autowired
-    private QwTagMapper qwTagMapper;
-
-    @Autowired
-    private QwTagGroupMapper qwTagGroupMapper;
-
-    @Autowired
-    private IQwTagGroupService qwTagGroupService;
-
-    @Autowired
-    private FsUserCourseMapper fsUserCourseMapper;
-
+    private FsVideoCourseTagMapper fsVideoCourseTagMapper;
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
 
@@ -84,10 +77,6 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
 
     @Value("${tag.rate.limit:30}")
     private Integer RATE_LIMIT_NUM;
-    /**
-     * 标签组最大数量
-     */
-    private static final Integer TAG_MAX_NUM = 100;
 
     /**
      * 接口限流
@@ -97,7 +86,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
     /**
      * 看课自动打标签开关
      */
-    @Value("${qw.enableAutoTag:0}")
+    @Value("${qw.enableAutoTag:1}")
     private Integer enableAutoTag;
 
     @PostConstruct
@@ -115,6 +104,8 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
         Map<Long, FsUserCourseVideo> courseVideoMap = fsUserCourseVideoMapper.selectAllMap();
         // 用户(这里用户用的是企微外部联系人ID)+videoId+status 唯一
 
+        Map<String, FsVideoCourseTag> fsVideoCourseTagMap = fsVideoCourseTagMapper.selectAll();
+
         // 先导课看课记录
         List<FsTagUpdateQueue> batchData = new ArrayList<>();
         for (FsCourseWatchLog item : logs) {
@@ -122,8 +113,6 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
             task.setCourseId(item.getCourseId());
             task.setVideoId(item.getVideoId());
             task.setCourseLogId(item.getLogId());
-            task.setTagId(null);
-            task.setTagName(null);
 
             task.setLogType(0);
             task.setOperationType(0);
@@ -150,12 +139,31 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
                 batchData.add(task);
                 continue;
             }
-            task.setTagGroupId(fsUserCourseVideo.getTagGroupId());
-            task.setTgId(fsUserCourseVideo.getTgId());
-            task.setWatchingTagId(fsUserCourseVideo.getWatchingTagId());
-            task.setWatchedTagId(fsUserCourseVideo.getWatchedTagId());
-            task.setWatchingTgId(fsUserCourseVideo.getWatchingTgId());
-            task.setWatchedTgId(fsUserCourseVideo.getWatchedTgId());
+            String compositeKey = String.format("%s_%s", corpId, fsUserCourseVideo.getVideoId());
+
+            FsVideoCourseTag fsVideoCourseTag = fsVideoCourseTagMap.get(compositeKey);
+            if(ObjectUtil.isNull(fsVideoCourseTag)) {
+                log.info("{},对应记录不存在!",compositeKey);
+                continue;
+            }
+            // 看课中-标签ID(表中的)
+            task.setWatchingTgId(fsVideoCourseTag.getWatchingTgId());
+            // 看课中-标签组ID(表中的)
+            task.setWatchingGroupId(fsVideoCourseTag.getWatchingGroupId());
+            // 完课-标签组ID(表中的)
+            task.setWatchedGroupId(fsVideoCourseTag.getWatchedGroupId());
+            // 完课-完课ID(表中的)
+            task.setWatchedTgId(fsVideoCourseTag.getWatchedTgId());
+
+            // 看课中-标签ID(企微)
+            task.setWatchingTagId(fsVideoCourseTag.getWatchingTagId());
+            // 看课中-标签组ID(企微)
+            task.setWatchingTgGroupId(fsVideoCourseTag.getWatchingGroupTgId());
+
+            // 完课-完课标签ID(企微)
+            task.setWatchedTagId(fsVideoCourseTag.getWatchedTagId());
+            // 完课-标签组ID(企微)
+            task.setWatchedTgGroupId(fsVideoCourseTag.getWatchedGroupTgId());
 
             if(ObjectUtil.equal(fsUserCourseVideo.getIsFirst(),1)) {
                 task.setIsFirst(1);
@@ -178,6 +186,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
             return;
         }
         Map<Long, FsUserCourseVideo> courseVideoMap = fsUserCourseVideoMapper.selectAllMap();
+        Map<String, FsVideoCourseTag> fsVideoCourseTagMap = fsVideoCourseTagMapper.selectAll();
 
         // 先导课看课记录
         List<FsTagUpdateQueue> batchData = new ArrayList<>();
@@ -186,8 +195,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
             task.setCourseId(item.getCourseId());
             task.setVideoId(item.getVideoId());
             task.setCourseLogId(item.getLogId());
-            task.setTagId(null);
-            task.setTagName(null);
+
             task.setOperationType(0);
             task.setStatus(0);
             task.setRetryCount(0);
@@ -213,12 +221,31 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
                 batchData.add(task);
                 continue;
             }
-            task.setTagGroupId(fsUserCourseVideo.getTagGroupId());
-            task.setTgId(fsUserCourseVideo.getTgId());
-            task.setWatchingTagId(fsUserCourseVideo.getWatchingTagId());
-            task.setWatchedTagId(fsUserCourseVideo.getWatchedTagId());
-            task.setWatchingTgId(fsUserCourseVideo.getWatchingTgId());
-            task.setWatchedTgId(fsUserCourseVideo.getWatchedTgId());
+            String compositeKey = String.format("%s_%s", corpId, fsUserCourseVideo.getVideoId());
+
+            FsVideoCourseTag fsVideoCourseTag = fsVideoCourseTagMap.get(compositeKey);
+            if(ObjectUtil.isNull(fsVideoCourseTag)) {
+                log.info("{},对应记录不存在!",compositeKey);
+                continue;
+            }
+            // 看课中-标签ID(表中的)
+            task.setWatchingTgId(fsVideoCourseTag.getWatchingTgId());
+            // 看课中-标签组ID(表中的)
+            task.setWatchingGroupId(fsVideoCourseTag.getWatchingGroupId());
+            // 完课-标签组ID(表中的)
+            task.setWatchedGroupId(fsVideoCourseTag.getWatchedGroupId());
+            // 完课-完课ID(表中的)
+            task.setWatchedTgId(fsVideoCourseTag.getWatchedTgId());
+
+            // 看课中-标签ID(企微)
+            task.setWatchingTagId(fsVideoCourseTag.getWatchingTagId());
+            // 看课中-标签组ID(企微)
+            task.setWatchingTgGroupId(fsVideoCourseTag.getWatchingGroupTgId());
+
+            // 完课-完课标签ID(企微)
+            task.setWatchedTagId(fsVideoCourseTag.getWatchedTagId());
+            // 完课-标签组ID(企微)
+            task.setWatchedTgGroupId(fsVideoCourseTag.getWatchedGroupTgId());
 
             if(ObjectUtil.equal(fsUserCourseVideo.getIsFirst(),1)) {
                 task.setIsFirst(1);
@@ -236,7 +263,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
     @Override
     public void handleData() {
         List<FsTagUpdateQueue> tasks = fsTagUpdateQueueMapper.selectPending();
-        if(CollectionUtils.isEmpty(tasks)){
+        if (CollectionUtils.isEmpty(tasks)) {
             log.info("找不到可处理的任务,已跳过!");
             return;
         }
@@ -276,7 +303,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
             Thread.currentThread().interrupt();
         }
 
-        if(CollectionUtils.isNotEmpty(tasks)){
+        if (CollectionUtils.isNotEmpty(tasks)) {
             fsTagUpdateQueueMapper.batchUpdateSelective(tasks);
         }
 
@@ -288,7 +315,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
             QwEditUserTagParam qwEditUserTagParam = new QwEditUserTagParam();
             QwExternalContact qwExternalContact = qwExternalContactMapper
                     .selectQwExternalContactById(fsTagUpdateQueue.getQwExternalContactId());
-            if(qwExternalContact == null) {
+            if (qwExternalContact == null) {
                 throw new IllegalArgumentException(String.format("企微外部联系人 %s 未找到!", fsTagUpdateQueue.getQwExternalContactId()));
             }
             qwEditUserTagParam.setUserid(qwExternalContact.getUserId());
@@ -297,7 +324,7 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
             rateLimiter.acquire();
 
             // 如果是看课中
-            if(ObjectUtil.equal(fsTagUpdateQueue.getLogType(),0)){
+            if (ObjectUtil.equal(fsTagUpdateQueue.getLogType(), 0)) {
                 qwEditUserTagParam.setAdd_tag(Collections.singletonList(fsTagUpdateQueue.getWatchingTagId()));
             } else {
                 // 已完课
@@ -305,19 +332,23 @@ public class FsTagUpdateServiceImpl implements FsTagUpdateService {
                 qwEditUserTagParam.setRemove_tag(Collections.singletonList(fsTagUpdateQueue.getWatchingTagId()));
             }
 
+            if (ObjectUtil.isNull(fsTagUpdateQueue.getCorpId())) {
+                throw new IllegalArgumentException("corpId为空!请检查一下");
+            }
             QwResult qwResult = qwApiService.editUserTag(qwEditUserTagParam, fsTagUpdateQueue.getCorpId());
+            log.info("返回结果: {}", JSON.toJSONString(qwResult));
             fsTagUpdateQueue.setPayload(JSON.toJSONString(qwEditUserTagParam));
             fsTagUpdateQueue.setResponse(JSON.toJSONString(qwResult));
             // 打标签成功
-            if(ObjectUtil.equal(qwResult.getErrcode(),0)) {
+            if (ObjectUtil.equal(qwResult.getErrcode(), 0)) {
                 fsTagUpdateQueue.setStatus(2);
-                fsTagUpdateQueue.setRetryCount(0);
+                fsTagUpdateQueue.setFailMsg("");
             } else {
                 throw new RuntimeException(String.format("打标签失败 原因: %s", JSON.toJSONString(qwResult)));
             }
-        } catch (Exception e){
+        } catch (Exception e) {
             fsTagUpdateQueue.setStatus(3);
-            fsTagUpdateQueue.setRetryCount(fsTagUpdateQueue.getRetryCount()+1);
+            fsTagUpdateQueue.setRetryCount(fsTagUpdateQueue.getRetryCount() + 1);
             fsTagUpdateQueue.setFailMsg(ExceptionUtils.getFullStackTrace(e));
             fsTagUpdateQueue.setNextExecuteTime(LocalDateTime.now().plusHours(1));
         }

+ 137 - 0
fs-service/src/main/java/com/fs/tag/service/impl/FsVideoCourseTagServiceImpl.java

@@ -0,0 +1,137 @@
+package com.fs.tag.service.impl;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.vo.FsUserCourseVideoVO;
+import com.fs.qw.domain.QwTag;
+import com.fs.qw.domain.QwTagGroup;
+import com.fs.qw.mapper.QwTagGroupMapper;
+import com.fs.qw.mapper.QwTagMapper;
+import com.fs.tag.domain.FsVideoCourseTag;
+import com.fs.tag.mapper.FsVideoCourseTagMapper;
+import com.fs.tag.service.IFsVideoCourseTagService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 视频小节看课标签关联Service业务层处理
+ *
+ * @author fs
+ * @date 2025-11-05
+ */
+@Service
+public class FsVideoCourseTagServiceImpl extends ServiceImpl<FsVideoCourseTagMapper, FsVideoCourseTag> implements IFsVideoCourseTagService {
+
+    /**
+     * 查询视频小节看课标签关联
+     *
+     * @param id 视频小节看课标签关联主键
+     * @return 视频小节看课标签关联
+     */
+    @Override
+    public FsVideoCourseTag selectFsVideoCourseTagById(Long id)
+    {
+        return baseMapper.selectFsVideoCourseTagById(id);
+    }
+
+
+    @Autowired
+    private QwTagGroupMapper qwTagGroupMapper;
+
+    @Autowired
+    private QwTagMapper qwTagMapper;
+    /**
+     * 查询视频小节看课标签关联列表
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 视频小节看课标签关联
+     */
+    @Override
+    public List<FsVideoCourseTag> selectFsVideoCourseTagList(FsVideoCourseTag fsVideoCourseTag)
+    {
+        List<FsVideoCourseTag> fsVideoCourseTags = baseMapper.selectFsVideoCourseTagList(fsVideoCourseTag);
+        for (FsVideoCourseTag item : fsVideoCourseTags) {
+            if(ObjectUtils.isNotNull(item.getWatchingGroupId())){
+                QwTagGroup qwTagGroup = qwTagGroupMapper.selectQwTagGroupById(item.getWatchingGroupId());
+                if(ObjectUtils.isNotNull(qwTagGroup)){
+                    item.setWatchingGroupName(qwTagGroup.getName());
+                }
+            }
+            if(ObjectUtils.isNotNull(item.getWatchedGroupId())){
+                QwTagGroup qwTagGroup = qwTagGroupMapper.selectQwTagGroupById(item.getWatchedGroupId());
+                if(ObjectUtils.isNotNull(qwTagGroup)){
+                    item.setWatchedGroupName(qwTagGroup.getName());
+                }
+            }
+
+            if(ObjectUtils.isNotNull(item.getWatchingTgId())){
+                QwTag qwTag = qwTagMapper.selectQwTagById(item.getWatchingTgId());
+                if(ObjectUtils.isNotNull(qwTag)){
+                    item.setWatchingTgName(qwTag.getName());
+                }
+            }
+
+            if(ObjectUtils.isNotNull(item.getWatchedTgId())) {
+                QwTag qwTag = qwTagMapper.selectQwTagById(item.getWatchedTgId());
+                if(ObjectUtils.isNotNull(qwTag)){
+                    item.setWatchedTgName(qwTag.getName());
+                }
+            }
+        }
+
+        return fsVideoCourseTags;
+    }
+
+    /**
+     * 新增视频小节看课标签关联
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 结果
+     */
+    @Override
+    public int insertFsVideoCourseTag(FsVideoCourseTag fsVideoCourseTag)
+    {
+        fsVideoCourseTag.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsVideoCourseTag(fsVideoCourseTag);
+    }
+
+    /**
+     * 修改视频小节看课标签关联
+     *
+     * @param fsVideoCourseTag 视频小节看课标签关联
+     * @return 结果
+     */
+    @Override
+    public int updateFsVideoCourseTag(FsVideoCourseTag fsVideoCourseTag)
+    {
+        fsVideoCourseTag.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsVideoCourseTag(fsVideoCourseTag);
+    }
+
+    /**
+     * 批量删除视频小节看课标签关联
+     *
+     * @param ids 需要删除的视频小节看课标签关联主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsVideoCourseTagByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsVideoCourseTagByIds(ids);
+    }
+
+    /**
+     * 删除视频小节看课标签关联信息
+     *
+     * @param id 视频小节看课标签关联主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsVideoCourseTagById(Long id)
+    {
+        return baseMapper.deleteFsVideoCourseTagById(id);
+    }
+}

+ 119 - 0
fs-service/src/main/resources/mapper/tag/FsVideoCourseTagMapper.xml

@@ -0,0 +1,119 @@
+<?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.tag.mapper.FsVideoCourseTagMapper">
+
+    <resultMap type="FsVideoCourseTag" id="FsVideoCourseTagResult">
+        <result property="id"    column="id"    />
+        <result property="corpId"    column="corp_id"    />
+        <result property="videoId"    column="video_id"    />
+        <result property="watchingGroupId"    column="watching_group_id"    />
+        <result property="watchedGroupId"    column="watched_group_id"    />
+        <result property="watchingTgId"    column="watching_tg_id"    />
+        <result property="watchedTgId"    column="watched_tg_id"    />
+        <result property="watchingGroupTgId"    column="watching_group_tag_id"    />
+        <result property="watchedGroupTgId"    column="watched_group_tag_id"    />
+        <result property="watchingTagId"    column="watching_tag_id"    />
+        <result property="watchedTagId"    column="watched_tag_id"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+    </resultMap>
+
+    <sql id="selectFsVideoCourseTagVo">
+        select id, corp_id, video_id, watching_group_id, watched_group_id, watching_tg_id, watched_tg_id, watching_group_tag_id, watched_group_tag_id, watching_tag_id, watched_tag_id, create_time, update_time, create_by, update_by from fs_video_course_tag
+    </sql>
+
+    <select id="selectFsVideoCourseTagList" parameterType="FsVideoCourseTag" resultMap="FsVideoCourseTagResult">
+        <include refid="selectFsVideoCourseTagVo"/>
+        <where>
+            <if test="corpId != null  and corpId != ''"> and corp_id = #{corpId}</if>
+            <if test="videoId != null "> and video_id = #{videoId}</if>
+            <if test="watchingGroupId != null "> and watching_group_id = #{watchingGroupId}</if>
+            <if test="watchedGroupId != null "> and watched_group_id = #{watchedGroupId}</if>
+            <if test="watchingTgId != null "> and watching_tg_id = #{watchingTgId}</if>
+            <if test="watchedTgId != null "> and watched_tg_id = #{watchedTgId}</if>
+            <if test="watchingGroupTgId != null  and watchingGroupTgId != ''"> and watching_group_tag_id = #{watchingGroupTgId}</if>
+            <if test="watchedGroupTgId != null  and watchedGroupTgId != ''"> and watched_group_tag_id = #{watchedGroupTgId}</if>
+            <if test="watchingTagId != null  and watchingTagId != ''"> and watching_tag_id = #{watchingTagId}</if>
+            <if test="watchedTagId != null  and watchedTagId != ''"> and watched_tag_id = #{watchedTagId}</if>
+        </where>
+    </select>
+
+    <select id="selectFsVideoCourseTagById" parameterType="Long" resultMap="FsVideoCourseTagResult">
+        <include refid="selectFsVideoCourseTagVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFsVideoCourseTag" parameterType="FsVideoCourseTag">
+        insert into fs_video_course_tag
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="corpId != null">corp_id,</if>
+            <if test="videoId != null">video_id,</if>
+            <if test="watchingGroupId != null">watching_group_id,</if>
+            <if test="watchedGroupId != null">watched_group_id,</if>
+            <if test="watchingTgId != null">watching_tg_id,</if>
+            <if test="watchedTgId != null">watched_tg_id,</if>
+            <if test="watchingGroupTgId != null">watching_group_tag_id,</if>
+            <if test="watchedGroupTgId != null">watched_group_tag_id,</if>
+            <if test="watchingTagId != null">watching_tag_id,</if>
+            <if test="watchedTagId != null">watched_tag_id,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="corpId != null">#{corpId},</if>
+            <if test="videoId != null">#{videoId},</if>
+            <if test="watchingGroupId != null">#{watchingGroupId},</if>
+            <if test="watchedGroupId != null">#{watchedGroupId},</if>
+            <if test="watchingTgId != null">#{watchingTgId},</if>
+            <if test="watchedTgId != null">#{watchedTgId},</if>
+            <if test="watchingGroupTgId != null">#{watchingGroupTgId},</if>
+            <if test="watchedGroupTgId != null">#{watchedGroupTgId},</if>
+            <if test="watchingTagId != null">#{watchingTagId},</if>
+            <if test="watchedTagId != null">#{watchedTagId},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+        </trim>
+    </insert>
+
+    <update id="updateFsVideoCourseTag" parameterType="FsVideoCourseTag">
+        update fs_video_course_tag
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="corpId != null">corp_id = #{corpId},</if>
+            <if test="videoId != null">video_id = #{videoId},</if>
+            <if test="watchingGroupId != null">watching_group_id = #{watchingGroupId},</if>
+            <if test="watchedGroupId != null">watched_group_id = #{watchedGroupId},</if>
+            <if test="watchingTgId != null">watching_tg_id = #{watchingTgId},</if>
+            <if test="watchedTgId != null">watched_tg_id = #{watchedTgId},</if>
+            <if test="watchingGroupTgId != null">watching_group_tag_id = #{watchingGroupTgId},</if>
+            <if test="watchedGroupTgId != null">watched_group_tag_id = #{watchedGroupTgId},</if>
+            <if test="watchingTagId != null">watching_tag_id = #{watchingTagId},</if>
+            <if test="watchedTagId != null">watched_tag_id = #{watchedTagId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsVideoCourseTagById" parameterType="Long">
+        delete from fs_video_course_tag where id = #{id}
+    </delete>
+
+    <delete id="deleteFsVideoCourseTagByIds" parameterType="String">
+        delete from fs_video_course_tag where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>