ソースを参照

1、关键词管理 新增失败问题,字段展示补全问题

yys 1 週間 前
コミット
80311842b8

+ 6 - 56
fs-admin-saas/src/main/java/com/fs/web/controller/system/SysKeywordController.java

@@ -4,7 +4,6 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
-import com.fs.common.core.redis.RedisCache;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.system.domain.SysKeyword;
 import com.fs.system.domain.SysKeyword;
@@ -12,15 +11,12 @@ import com.fs.system.service.ISysKeywordService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
-import javax.annotation.PostConstruct;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.stream.Collectors;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 
 /**
 /**
  * 系统关键字Controller
  * 系统关键字Controller
@@ -35,14 +31,6 @@ public class SysKeywordController extends BaseController
     @Autowired
     @Autowired
     private ISysKeywordService sysKeywordService;
     private ISysKeywordService sysKeywordService;
 
 
-    @Autowired
-    RedisCache redisCache;
-
-    @Autowired
-    public RedisTemplate<String,String> redisTemplate;
-
-    private static final String REDIS_KEY = "sys:keywords";
-
     /**
     /**
      * 查询系统关键字列表
      * 查询系统关键字列表
      */
      */
@@ -50,7 +38,6 @@ public class SysKeywordController extends BaseController
     @GetMapping("/list")
     @GetMapping("/list")
     public R list(SysKeyword sysKeyword)
     public R list(SysKeyword sysKeyword)
     {
     {
-//        startPage();
         PageHelper.startPage(sysKeyword.getPageNum(), sysKeyword.getPageSize());
         PageHelper.startPage(sysKeyword.getPageNum(), sysKeyword.getPageSize());
         List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);
         List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);
 
 
@@ -92,10 +79,7 @@ public class SysKeywordController extends BaseController
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody SysKeyword sysKeyword)
     public AjaxResult add(@RequestBody SysKeyword sysKeyword)
     {
     {
-        int i = sysKeywordService.insertSysKeyword(sysKeyword);
-        // 缓存
-        redisTemplate.opsForSet().add(REDIS_KEY, sysKeyword.getKeyword());
-        return toAjax(i);
+        return toAjax(sysKeywordService.insertSysKeyword(sysKeyword));
     }
     }
 
 
     /**
     /**
@@ -106,14 +90,7 @@ public class SysKeywordController extends BaseController
     @PutMapping
     @PutMapping
     public AjaxResult edit(@RequestBody SysKeyword sysKeyword)
     public AjaxResult edit(@RequestBody SysKeyword sysKeyword)
     {
     {
-        //获取之前的数据
-        SysKeyword sysKeywordOld = sysKeywordService.selectSysKeywordById(sysKeyword.getKeywordId());
-        String keywordOld = sysKeywordOld.getKeyword();
-        int i = sysKeywordService.updateSysKeyword(sysKeyword);
-        // 更新缓存
-        redisTemplate.opsForSet().remove(REDIS_KEY, keywordOld);
-        redisTemplate.opsForSet().add(REDIS_KEY, sysKeyword.getKeyword());
-        return toAjax(i);
+        return toAjax(sysKeywordService.updateSysKeyword(sysKeyword));
     }
     }
 
 
     /**
     /**
@@ -124,33 +101,6 @@ public class SysKeywordController extends BaseController
 	@DeleteMapping("/{keywordIds}")
 	@DeleteMapping("/{keywordIds}")
     public AjaxResult remove(@PathVariable Long[] keywordIds)
     public AjaxResult remove(@PathVariable Long[] keywordIds)
     {
     {
-        List<SysKeyword> sysKeywords = sysKeywordService.selectSysKeywordByIds(keywordIds);
-        int i = sysKeywordService.deleteSysKeywordByIds(keywordIds);
-        if (!CollectionUtils.isEmpty(sysKeywords)) {
-            redisTemplate.opsForSet().remove(REDIS_KEY, sysKeywords.stream().map(SysKeyword::getKeyword).toArray(String[]::new));
-        }
-        return toAjax(i);
-    }
-
-    /**
-     * 启动加载全部关键字到缓存
-     */
-    @PostConstruct
-    public void initKeywords() {
-        try {
-            SysKeyword sysKeywordParam = new SysKeyword();
-            List<SysKeyword> sysKeywords = sysKeywordService.selectSysKeywordList(sysKeywordParam);
-            List<String> keywords = sysKeywords.stream()
-                    .map(SysKeyword::getKeyword)
-                    .filter(k -> k != null && !k.isEmpty())
-                    .collect(Collectors.toList());
-
-            if (!keywords.isEmpty()) {
-                redisTemplate.opsForSet().add(REDIS_KEY, keywords.toArray(new String[0]));
-            }
-            System.out.println("加载全部关键字到缓存");
-        } catch (Exception e) {
-            System.err.println("警告: 加载关键字到Redis缓存失败,应用继续启动: " + e.getMessage());
-        }
+        return toAjax(sysKeywordService.deleteSysKeywordByIds(keywordIds));
     }
     }
 }
 }

+ 106 - 157
fs-admin/src/main/java/com/fs/web/controller/system/SysKeywordController.java

@@ -1,157 +1,106 @@
-package com.fs.web.controller.system;
-
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.core.domain.R;
-import com.fs.common.core.redis.RedisCache;
-import com.fs.common.enums.BusinessType;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.system.domain.SysKeyword;
-import com.fs.system.service.ISysKeywordService;
-import com.github.pagehelper.PageHelper;
-import com.github.pagehelper.PageInfo;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.PostConstruct;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * 系统关键字Controller
- *
- * @author fs
- * @date 2025-05-14
- */
-@RestController
-@RequestMapping("/system/keyword")
-public class SysKeywordController extends BaseController
-{
-    @Autowired
-    private ISysKeywordService sysKeywordService;
-
-    @Autowired
-    RedisCache redisCache;
-
-    @Autowired
-    public RedisTemplate<String,String> redisTemplate;
-
-    private static final String REDIS_KEY = "sys:keywords";
-
-    /**
-     * 查询系统关键字列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:keyword:list')")
-    @GetMapping("/list")
-    public R list(SysKeyword sysKeyword)
-    {
-//        startPage();
-        PageHelper.startPage(sysKeyword.getPageNum(), sysKeyword.getPageSize());
-        List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);
-
-        PageInfo<SysKeyword> pageInfo = new PageInfo<>(list);
-        Map<String, Object> result = new HashMap<>();
-        result.put("rows", pageInfo.getList());
-        result.put("total", pageInfo.getTotal());
-        return R.ok(result);
-    }
-
-    /**
-     * 导出系统关键字列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:keyword:export')")
-    @Log(title = "系统关键字", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(SysKeyword sysKeyword)
-    {
-        List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);
-        ExcelUtil<SysKeyword> util = new ExcelUtil<SysKeyword>(SysKeyword.class);
-        return util.exportExcel(list, "系统关键字数据");
-    }
-
-    /**
-     * 获取系统关键字详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:keyword:query')")
-    @GetMapping(value = "/{keywordId}")
-    public AjaxResult getInfo(@PathVariable("keywordId") Long keywordId)
-    {
-        return AjaxResult.success(sysKeywordService.selectSysKeywordById(keywordId));
-    }
-
-    /**
-     * 新增系统关键字
-     */
-    @PreAuthorize("@ss.hasPermi('system:keyword:add')")
-    @Log(title = "系统关键字", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody SysKeyword sysKeyword)
-    {
-        int i = sysKeywordService.insertSysKeyword(sysKeyword);
-        // 缓存
-        redisTemplate.opsForSet().add(REDIS_KEY, sysKeyword.getKeyword());
-        return toAjax(i);
-    }
-
-    /**
-     * 修改系统关键字
-     */
-    @PreAuthorize("@ss.hasPermi('system:keyword:edit')")
-    @Log(title = "系统关键字", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody SysKeyword sysKeyword)
-    {
-        //获取之前的数据
-        SysKeyword sysKeywordOld = sysKeywordService.selectSysKeywordById(sysKeyword.getKeywordId());
-        String keywordOld = sysKeywordOld.getKeyword();
-        int i = sysKeywordService.updateSysKeyword(sysKeyword);
-        // 更新缓存
-        redisTemplate.opsForSet().remove(REDIS_KEY, keywordOld);
-        redisTemplate.opsForSet().add(REDIS_KEY, sysKeyword.getKeyword());
-        return toAjax(i);
-    }
-
-    /**
-     * 删除系统关键字
-     */
-    @PreAuthorize("@ss.hasPermi('system:keyword:remove')")
-    @Log(title = "系统关键字", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{keywordIds}")
-    public AjaxResult remove(@PathVariable Long[] keywordIds)
-    {
-        List<SysKeyword> sysKeywords = sysKeywordService.selectSysKeywordByIds(keywordIds);
-        int i = sysKeywordService.deleteSysKeywordByIds(keywordIds);
-        if (!CollectionUtils.isEmpty(sysKeywords)) {
-            redisTemplate.opsForSet().remove(REDIS_KEY, sysKeywords.stream().map(SysKeyword::getKeyword).toArray(String[]::new));
-        }
-        return toAjax(i);
-    }
-
-    /**
-     * 启动加载全部关键字到缓存
-     */
-    @PostConstruct
-    public void initKeywords() {
-        try {
-            SysKeyword sysKeywordParam = new SysKeyword();
-            List<SysKeyword> sysKeywords = sysKeywordService.selectSysKeywordList(sysKeywordParam);
-            List<String> keywords = sysKeywords.stream()
-                    .map(SysKeyword::getKeyword)
-                    .filter(k -> k != null && !k.isEmpty())
-                    .collect(Collectors.toList());
-
-            if (!keywords.isEmpty()) {
-                redisTemplate.opsForSet().add(REDIS_KEY, keywords.toArray(new String[0]));
-            }
-            System.out.println("加载全部关键字到缓存");
-        } catch (Exception e) {
-            System.err.println("警告: 加载关键字到Redis缓存失败,应用继续启动: " + e.getMessage());
-        }
-    }
-}
+package com.fs.web.controller.system;

+

+import com.fs.common.annotation.Log;

+import com.fs.common.core.controller.BaseController;

+import com.fs.common.core.domain.AjaxResult;

+import com.fs.common.core.domain.R;

+import com.fs.common.enums.BusinessType;

+import com.fs.common.utils.poi.ExcelUtil;

+import com.fs.system.domain.SysKeyword;

+import com.fs.system.service.ISysKeywordService;

+import com.github.pagehelper.PageHelper;

+import com.github.pagehelper.PageInfo;

+import org.springframework.beans.factory.annotation.Autowired;

+import org.springframework.security.access.prepost.PreAuthorize;

+import org.springframework.web.bind.annotation.*;

+

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+

+/**

+ * 系统关键字Controller

+ *

+ * @author fs

+ * @date 2025-05-14

+ */

+@RestController

+@RequestMapping("/system/keyword")

+public class SysKeywordController extends BaseController

+{

+    @Autowired

+    private ISysKeywordService sysKeywordService;

+

+    /**

+     * 查询系统关键字列表

+     */

+    @PreAuthorize("@ss.hasPermi('system:keyword:list')")

+    @GetMapping("/list")

+    public R list(SysKeyword sysKeyword)

+    {

+        PageHelper.startPage(sysKeyword.getPageNum(), sysKeyword.getPageSize());

+        List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);

+

+        PageInfo<SysKeyword> pageInfo = new PageInfo<>(list);

+        Map<String, Object> result = new HashMap<>();

+        result.put("rows", pageInfo.getList());

+        result.put("total", pageInfo.getTotal());

+        return R.ok(result);

+    }

+

+    /**

+     * 导出系统关键字列表

+     */

+    @PreAuthorize("@ss.hasPermi('system:keyword:export')")

+    @Log(title = "系统关键字", businessType = BusinessType.EXPORT)

+    @GetMapping("/export")

+    public AjaxResult export(SysKeyword sysKeyword)

+    {

+        List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);

+        ExcelUtil<SysKeyword> util = new ExcelUtil<SysKeyword>(SysKeyword.class);

+        return util.exportExcel(list, "系统关键字数据");

+    }

+

+    /**

+     * 获取系统关键字详细信息

+     */

+    @PreAuthorize("@ss.hasPermi('system:keyword:query')")

+    @GetMapping(value = "/{keywordId}")

+    public AjaxResult getInfo(@PathVariable("keywordId") Long keywordId)

+    {

+        return AjaxResult.success(sysKeywordService.selectSysKeywordById(keywordId));

+    }

+

+    /**

+     * 新增系统关键字

+     */

+    @PreAuthorize("@ss.hasPermi('system:keyword:add')")

+    @Log(title = "系统关键字", businessType = BusinessType.INSERT)

+    @PostMapping

+    public AjaxResult add(@RequestBody SysKeyword sysKeyword)

+    {

+        return toAjax(sysKeywordService.insertSysKeyword(sysKeyword));

+    }

+

+    /**

+     * 修改系统关键字

+     */

+    @PreAuthorize("@ss.hasPermi('system:keyword:edit')")

+    @Log(title = "系统关键字", businessType = BusinessType.UPDATE)

+    @PutMapping

+    public AjaxResult edit(@RequestBody SysKeyword sysKeyword)

+    {

+        return toAjax(sysKeywordService.updateSysKeyword(sysKeyword));

+    }

+

+    /**

+     * 删除系统关键字

+     */

+    @PreAuthorize("@ss.hasPermi('system:keyword:remove')")

+    @Log(title = "系统关键字", businessType = BusinessType.DELETE)

+	@DeleteMapping("/{keywordIds}")

+    public AjaxResult remove(@PathVariable Long[] keywordIds)

+    {

+        return toAjax(sysKeywordService.deleteSysKeywordByIds(keywordIds));

+    }

+}


+ 9 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchCommentServiceImpl.java

@@ -7,6 +7,7 @@ import java.util.stream.Collectors;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.course.param.FsCourseWatchCommentListParam;
 import com.fs.course.param.FsCourseWatchCommentListParam;
 import com.fs.course.param.FsCourseWatchCommentPageParam;
 import com.fs.course.param.FsCourseWatchCommentPageParam;
@@ -14,6 +15,7 @@ import com.fs.course.param.FsCourseWatchCommentSaveParam;
 import com.fs.course.vo.FsCourseWatchCommentListVO;
 import com.fs.course.vo.FsCourseWatchCommentListVO;
 import com.fs.course.vo.FsCourseWatchCommentVO;
 import com.fs.course.vo.FsCourseWatchCommentVO;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.system.constant.SysKeywordConstants;
 import com.fs.system.domain.SysKeyword;
 import com.fs.system.domain.SysKeyword;
 import com.fs.system.mapper.SysKeywordMapper;
 import com.fs.system.mapper.SysKeywordMapper;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
@@ -33,7 +35,7 @@ import com.fs.course.service.IFsCourseWatchCommentService;
 @Service
 @Service
 public class FsCourseWatchCommentServiceImpl extends ServiceImpl<FsCourseWatchCommentMapper, FsCourseWatchComment> implements IFsCourseWatchCommentService {
 public class FsCourseWatchCommentServiceImpl extends ServiceImpl<FsCourseWatchCommentMapper, FsCourseWatchComment> implements IFsCourseWatchCommentService {
 
 
-    private static final String REDIS_KEY = "sys:keywords";
+    private static final String REDIS_KEY = SysKeywordConstants.redisKey(SysKeywordConstants.TYPE_COURSE_COMMENT);
 
 
     @Autowired
     @Autowired
     RedisCache redisCache;
     RedisCache redisCache;
@@ -127,12 +129,16 @@ public class FsCourseWatchCommentServiceImpl extends ServiceImpl<FsCourseWatchCo
         Set<String>  keywords = redisTemplate.opsForSet().members(REDIS_KEY);
         Set<String>  keywords = redisTemplate.opsForSet().members(REDIS_KEY);
         if(keywords == null || keywords.isEmpty()){
         if(keywords == null || keywords.isEmpty()){
             SysKeyword sysKeywordParam = new SysKeyword();
             SysKeyword sysKeywordParam = new SysKeyword();
+            sysKeywordParam.setKeywordType(SysKeywordConstants.TYPE_COURSE_COMMENT);
             List<SysKeyword> sysKeywords = mapper.selectSysKeywordList(sysKeywordParam);
             List<SysKeyword> sysKeywords = mapper.selectSysKeywordList(sysKeywordParam);
-            keywords = sysKeywords.stream().map(SysKeyword::getKeyword).collect(Collectors.toSet());
+            keywords = sysKeywords.stream()
+                    .map(SysKeyword::getKeyword)
+                    .filter(StringUtils::isNotEmpty)
+                    .collect(Collectors.toSet());
         }
         }
         if(!keywords.isEmpty()){
         if(!keywords.isEmpty()){
             for (String keyword : keywords) {
             for (String keyword : keywords) {
-                if (param.getContent().contains(keyword)) {
+                if (StringUtils.isNotEmpty(keyword) && param.getContent().contains(keyword)) {
                     //标记用户为黑名单,并且不保存数据
                     //标记用户为黑名单,并且不保存数据
                     qwExternalContactMapper.updateQwExternalContactByFsUserId(1, param.getUserId());
                     qwExternalContactMapper.updateQwExternalContactByFsUserId(1, param.getUserId());
                     return R.ok().put("status", false);
                     return R.ok().put("status", false);

+ 14 - 3
fs-service/src/main/java/com/fs/system/domain/SysKeyword.java

@@ -29,14 +29,25 @@ public class SysKeyword extends BaseEntity{
     @Excel(name = "关键字")
     @Excel(name = "关键字")
     private String keyword;
     private String keyword;
 
 
-//    /** 类型:1-看课弹幕; */
-//    @Excel(name = "类型:1-看课弹幕;")
-//    private Integer type;
+    /**
+     * 关键字内容(前端字段 keywordContent,可与 keyword 二选一)
+     */
+    private String keywordContent;
+
+    /**
+     * 关键字类型,字典 keyword_type(1-看课弹幕等)
+     */
+    @Excel(name = "关键字类型", dictType = "keyword_type")
+    private Integer keywordType;
 
 
     /** 所属公司 */
     /** 所属公司 */
     @Excel(name = "所属公司")
     @Excel(name = "所属公司")
     private Long companyId;
     private Long companyId;
 
 
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remark;
+
     @TableField(exist = false)
     @TableField(exist = false)
     @Excel(name = "类型名称")
     @Excel(name = "类型名称")
     private String typeName;
     private String typeName;

+ 102 - 22
fs-service/src/main/java/com/fs/system/service/impl/SysKeywordServiceImpl.java

@@ -1,12 +1,22 @@
 package com.fs.system.service.impl;
 package com.fs.system.service.impl;
 
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.system.constant.SysKeywordConstants;
 import com.fs.system.domain.SysKeyword;
 import com.fs.system.domain.SysKeyword;
 import com.fs.system.mapper.SysKeywordMapper;
 import com.fs.system.mapper.SysKeywordMapper;
 import com.fs.system.service.ISysKeywordService;
 import com.fs.system.service.ISysKeywordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.PostConstruct;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 系统关键字Service业务层处理
  * 系统关键字Service业务层处理
@@ -17,11 +27,11 @@ import java.util.List;
 @Service
 @Service
 public class SysKeywordServiceImpl extends ServiceImpl<SysKeywordMapper, SysKeyword> implements ISysKeywordService {
 public class SysKeywordServiceImpl extends ServiceImpl<SysKeywordMapper, SysKeyword> implements ISysKeywordService {
 
 
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
     /**
     /**
      * 查询系统关键字
      * 查询系统关键字
-     *
-     * @param keywordId 系统关键字主键
-     * @return 系统关键字
      */
      */
     @Override
     @Override
     public SysKeyword selectSysKeywordById(Long keywordId)
     public SysKeyword selectSysKeywordById(Long keywordId)
@@ -31,9 +41,6 @@ public class SysKeywordServiceImpl extends ServiceImpl<SysKeywordMapper, SysKeyw
 
 
     /**
     /**
      * 查询系统关键字列表
      * 查询系统关键字列表
-     *
-     * @param sysKeyword 系统关键字
-     * @return 系统关键字
      */
      */
     @Override
     @Override
     public List<SysKeyword> selectSysKeywordList(SysKeyword sysKeyword)
     public List<SysKeyword> selectSysKeywordList(SysKeyword sysKeyword)
@@ -43,56 +50,129 @@ public class SysKeywordServiceImpl extends ServiceImpl<SysKeywordMapper, SysKeyw
 
 
     /**
     /**
      * 新增系统关键字
      * 新增系统关键字
-     *
-     * @param sysKeyword 系统关键字
-     * @return 结果
      */
      */
     @Override
     @Override
     public int insertSysKeyword(SysKeyword sysKeyword)
     public int insertSysKeyword(SysKeyword sysKeyword)
     {
     {
+        normalize(sysKeyword);
+        validate(sysKeyword);
         sysKeyword.setCreateTime(DateUtils.getNowDate());
         sysKeyword.setCreateTime(DateUtils.getNowDate());
-        return baseMapper.insertSysKeyword(sysKeyword);
+        int rows = baseMapper.insertSysKeyword(sysKeyword);
+        if (rows > 0) {
+            addKeywordToCache(sysKeyword.getKeyword(), sysKeyword.getKeywordType());
+        }
+        return rows;
     }
     }
 
 
     /**
     /**
      * 修改系统关键字
      * 修改系统关键字
-     *
-     * @param sysKeyword 系统关键字
-     * @return 结果
      */
      */
     @Override
     @Override
     public int updateSysKeyword(SysKeyword sysKeyword)
     public int updateSysKeyword(SysKeyword sysKeyword)
     {
     {
+        normalize(sysKeyword);
+        validate(sysKeyword);
+        SysKeyword old = baseMapper.selectSysKeywordById(sysKeyword.getKeywordId());
         sysKeyword.setUpdateTime(DateUtils.getNowDate());
         sysKeyword.setUpdateTime(DateUtils.getNowDate());
-        return baseMapper.updateSysKeyword(sysKeyword);
+        int rows = baseMapper.updateSysKeyword(sysKeyword);
+        if (rows > 0 && old != null) {
+            removeKeywordFromCache(old.getKeyword(), old.getKeywordType());
+            addKeywordToCache(sysKeyword.getKeyword(), sysKeyword.getKeywordType());
+        }
+        return rows;
     }
     }
 
 
     /**
     /**
      * 批量删除系统关键字
      * 批量删除系统关键字
-     *
-     * @param keywordIds 需要删除的系统关键字主键
-     * @return 结果
      */
      */
     @Override
     @Override
     public int deleteSysKeywordByIds(Long[] keywordIds)
     public int deleteSysKeywordByIds(Long[] keywordIds)
     {
     {
-        return baseMapper.deleteSysKeywordByIds(keywordIds);
+        List<SysKeyword> sysKeywords = baseMapper.selectSysKeywordByIds(keywordIds);
+        int rows = baseMapper.deleteSysKeywordByIds(keywordIds);
+        if (rows > 0 && !CollectionUtils.isEmpty(sysKeywords)) {
+            sysKeywords.forEach(k -> removeKeywordFromCache(k.getKeyword(), k.getKeywordType()));
+        }
+        return rows;
     }
     }
 
 
     /**
     /**
      * 删除系统关键字信息
      * 删除系统关键字信息
-     *
-     * @param keywordId 系统关键字主键
-     * @return 结果
      */
      */
     @Override
     @Override
     public int deleteSysKeywordById(Long keywordId)
     public int deleteSysKeywordById(Long keywordId)
     {
     {
-        return baseMapper.deleteSysKeywordById(keywordId);
+        SysKeyword old = baseMapper.selectSysKeywordById(keywordId);
+        int rows = baseMapper.deleteSysKeywordById(keywordId);
+        if (rows > 0 && old != null) {
+            removeKeywordFromCache(old.getKeyword(), old.getKeywordType());
+        }
+        return rows;
     }
     }
 
 
     @Override
     @Override
     public List<SysKeyword> selectSysKeywordByIds(Long[] keywordIds) {
     public List<SysKeyword> selectSysKeywordByIds(Long[] keywordIds) {
         return baseMapper.selectSysKeywordByIds(keywordIds);
         return baseMapper.selectSysKeywordByIds(keywordIds);
     }
     }
+
+    /**
+     * 启动时按类型加载关键字到 Redis
+     */
+    @PostConstruct
+    public void initKeywordsCache() {
+        try {
+            List<SysKeyword> sysKeywords = baseMapper.selectSysKeywordList(new SysKeyword());
+            Map<Integer, List<String>> grouped = sysKeywords.stream()
+                    .filter(k -> StringUtils.isNotEmpty(k.getKeyword()))
+                    .collect(Collectors.groupingBy(
+                            k -> k.getKeywordType() != null ? k.getKeywordType() : SysKeywordConstants.TYPE_COURSE_COMMENT,
+                            Collectors.mapping(SysKeyword::getKeyword, Collectors.toList())
+                    ));
+            grouped.forEach((type, keywords) -> {
+                String redisKey = SysKeywordConstants.redisKey(type);
+                redisTemplate.delete(redisKey);
+                if (!keywords.isEmpty()) {
+                    redisTemplate.opsForSet().add(redisKey, keywords.toArray(new String[0]));
+                }
+            });
+        } catch (Exception e) {
+            System.err.println("警告: 加载关键字到Redis缓存失败,应用继续启动: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 归一化前端字段:keywordContent 可回填 keyword,默认类型为看课弹幕
+     */
+    private void normalize(SysKeyword sysKeyword) {
+        if (StringUtils.isEmpty(sysKeyword.getKeyword()) && StringUtils.isNotEmpty(sysKeyword.getKeywordContent())) {
+            sysKeyword.setKeyword(sysKeyword.getKeywordContent().trim());
+        }
+        if (sysKeyword.getKeywordType() == null) {
+            sysKeyword.setKeywordType(SysKeywordConstants.TYPE_COURSE_COMMENT);
+        }
+        if (StringUtils.isNotEmpty(sysKeyword.getKeyword())) {
+            sysKeyword.setKeyword(sysKeyword.getKeyword().trim());
+        }
+    }
+
+    private void validate(SysKeyword sysKeyword) {
+        if (StringUtils.isEmpty(sysKeyword.getKeyword())) {
+            throw new ServiceException("关键字不能为空");
+        }
+        if (sysKeyword.getKeywordType() == null) {
+            throw new ServiceException("关键字类型不能为空");
+        }
+    }
+
+    private void addKeywordToCache(String keyword, Integer keywordType) {
+        if (StringUtils.isNotEmpty(keyword)) {
+            redisTemplate.opsForSet().add(SysKeywordConstants.redisKey(keywordType), keyword);
+        }
+    }
+
+    private void removeKeywordFromCache(String keyword, Integer keywordType) {
+        if (StringUtils.isNotEmpty(keyword)) {
+            redisTemplate.opsForSet().remove(SysKeywordConstants.redisKey(keywordType), keyword);
+        }
+    }
 }
 }

+ 3 - 0
fs-service/src/main/resources/db/20250530-初始化表结构.sql

@@ -9,6 +9,9 @@ DROP TABLE IF EXISTS `sys_keyword`;
 CREATE TABLE `sys_keyword`  (
 CREATE TABLE `sys_keyword`  (
                                 `keyword_id` bigint NOT NULL AUTO_INCREMENT COMMENT '关键字id',
                                 `keyword_id` bigint NOT NULL AUTO_INCREMENT COMMENT '关键字id',
                                 `keyword` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '关键字',
                                 `keyword` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '关键字',
+                                `keyword_type` int NULL DEFAULT 1 COMMENT '关键字类型,字典 keyword_type',
+                                `keyword_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '关键字内容/扩展说明',
+                                `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
                                 `company_id` bigint NULL DEFAULT NULL COMMENT '所属公司',
                                 `company_id` bigint NULL DEFAULT NULL COMMENT '所属公司',
                                 `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
                                 `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
                                 `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
                                 `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',

+ 1 - 1
fs-service/src/main/resources/db/tenant-initData.sql

@@ -1426,7 +1426,7 @@ INSERT INTO `sys_dict_data` VALUES (1426, 12, '修改红包', 'update_sop_temp_r
 INSERT INTO `sys_dict_data` VALUES (1427, 11, '修改课程', 'update_sop_temp_scourse', 'company_sop_role', NULL, NULL, 'N', '0', 'admin', '2025-05-07 14:16:45', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1427, 11, '修改课程', 'update_sop_temp_scourse', 'company_sop_role', NULL, NULL, 'N', '0', 'admin', '2025-05-07 14:16:45', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1428, 5, '课程模板', '11', 'sys_qw_sop_type', NULL, NULL, 'N', '0', 'admin', '2025-04-21 14:05:28', 'admin', '2025-05-27 19:37:42', NULL);
 INSERT INTO `sys_dict_data` VALUES (1428, 5, '课程模板', '11', 'sys_qw_sop_type', NULL, NULL, 'N', '0', 'admin', '2025-04-21 14:05:28', 'admin', '2025-05-27 19:37:42', NULL);
 INSERT INTO `sys_dict_data` VALUES (1429, 3, '抖音', '3', 'ad_type', NULL, 'default', 'N', '0', 'admin', '2025-05-27 14:10:17', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1429, 3, '抖音', '3', 'ad_type', NULL, 'default', 'N', '0', 'admin', '2025-05-27 14:10:17', '', NULL, NULL);
-INSERT INTO `sys_dict_data` VALUES (1430, 0, '看课弹幕', '1376', 'keyword_type', NULL, 'default', 'N', '0', 'admin', '2025-05-27 18:28:25', '', NULL, NULL);
+INSERT INTO `sys_dict_data` VALUES (1430, 0, '看课弹幕', '1', 'keyword_type', NULL, 'default', 'N', '0', 'admin', '2025-05-27 18:28:25', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1443, 6, '客户群群发', '6', 'sys_qw_sop_course_type', NULL, 'default', 'N', '1', 'sgw', '2025-04-16 19:55:21', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1443, 6, '客户群群发', '6', 'sys_qw_sop_course_type', NULL, 'default', 'N', '1', 'sgw', '2025-04-16 19:55:21', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1444, 7, '欢迎语补发', '7', 'sys_qw_sop_course_type', NULL, 'default', 'N', '1', 'sgw', '2025-04-16 19:55:35', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1444, 7, '欢迎语补发', '7', 'sys_qw_sop_course_type', NULL, 'default', 'N', '1', 'sgw', '2025-04-16 19:55:35', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1445, 8, 'AI对话', '8', 'sys_qw_sop_course_type', NULL, 'default', 'N', '1', 'sgw', '2025-04-16 19:55:55', '', NULL, NULL);
 INSERT INTO `sys_dict_data` VALUES (1445, 8, 'AI对话', '8', 'sys_qw_sop_course_type', NULL, 'default', 'N', '1', 'sgw', '2025-04-16 19:55:55', '', NULL, NULL);

+ 3 - 0
fs-service/src/main/resources/db/tenant-initTable.sql

@@ -16434,6 +16434,9 @@ CREATE TABLE `sys_keyword`
 (
 (
     `keyword_id`  bigint NOT NULL AUTO_INCREMENT COMMENT '关键字id',
     `keyword_id`  bigint NOT NULL AUTO_INCREMENT COMMENT '关键字id',
     `keyword`     varchar(50)   NULL DEFAULT NULL COMMENT '关键字',
     `keyword`     varchar(50)   NULL DEFAULT NULL COMMENT '关键字',
+    `keyword_type` int NULL DEFAULT 1 COMMENT '关键字类型,字典 keyword_type',
+    `keyword_content` varchar(500) NULL DEFAULT NULL COMMENT '关键字内容/扩展说明',
+    `remark` varchar(500) NULL DEFAULT NULL COMMENT '备注',
     `company_id`  bigint NULL DEFAULT NULL COMMENT '所属公司',
     `company_id`  bigint NULL DEFAULT NULL COMMENT '所属公司',
     `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
     `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
     `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
     `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',

+ 26 - 4
fs-service/src/main/resources/mapper/system/SysKeywordMapper.xml

@@ -7,34 +7,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="SysKeyword" id="SysKeywordResult">
     <resultMap type="SysKeyword" id="SysKeywordResult">
         <result property="keywordId"    column="keyword_id"    />
         <result property="keywordId"    column="keyword_id"    />
         <result property="keyword"    column="keyword"    />
         <result property="keyword"    column="keyword"    />
+        <result property="keywordContent"    column="keyword_content"    />
+        <result property="keywordType"    column="keyword_type"    />
+        <result property="remark"    column="remark"    />
         <result property="companyId"    column="company_id"    />
         <result property="companyId"    column="company_id"    />
         <result property="createTime"    column="create_time"    />
         <result property="createTime"    column="create_time"    />
         <result property="updateTime"    column="update_time"    />
         <result property="updateTime"    column="update_time"    />
+        <result property="typeName"    column="type_name"    />
+        <result property="companyName"    column="company_name"    />
     </resultMap>
     </resultMap>
 
 
     <sql id="selectSysKeyword">
     <sql id="selectSysKeyword">
-        select keyword_id, keyword, company_id, create_time, update_time from sys_keyword
+        select keyword_id, keyword, keyword_type, keyword_content, remark, company_id, create_time, update_time from sys_keyword
     </sql>
     </sql>
 
 
     <sql id="selectSysKeywordVo">
     <sql id="selectSysKeywordVo">
         SELECT
         SELECT
-            keyword_id,
-            keyword,
+            sys_keyword.keyword_id,
+            sys_keyword.keyword,
+            sys_keyword.keyword_type,
+            sys_keyword.keyword_content,
+            sys_keyword.remark,
             sys_keyword.company_id,
             sys_keyword.company_id,
             sys_keyword.create_time,
             sys_keyword.create_time,
             sys_keyword.update_time,
             sys_keyword.update_time,
+            d.dict_label AS type_name,
             company.company_name
             company.company_name
         FROM
         FROM
             sys_keyword
             sys_keyword
                 LEFT JOIN company ON company.company_id = sys_keyword.company_id
                 LEFT JOIN company ON company.company_id = sys_keyword.company_id
+                LEFT JOIN sys_dict_data d ON d.dict_type = 'keyword_type'
+                    AND d.dict_value = CAST(sys_keyword.keyword_type AS CHAR)
     </sql>
     </sql>
 
 
     <select id="selectSysKeywordList" resultMap="SysKeywordResult">
     <select id="selectSysKeywordList" resultMap="SysKeywordResult">
         <include refid="selectSysKeywordVo"/>
         <include refid="selectSysKeywordVo"/>
         <where>
         <where>
-            <if test="keyword != null  and keyword != ''"> and keyword like concat('%', #{keyword}, '%')</if>
+            <if test="keyword != null  and keyword != ''"> and sys_keyword.keyword like concat('%', #{keyword}, '%')</if>
+            <if test="keywordType != null"> and sys_keyword.keyword_type = #{keywordType}</if>
             <if test="companyId != null "> and sys_keyword.company_id = #{companyId}</if>
             <if test="companyId != null "> and sys_keyword.company_id = #{companyId}</if>
         </where>
         </where>
+        order by sys_keyword.keyword_id desc
     </select>
     </select>
 
 
     <select id="selectSysKeywordById" resultMap="SysKeywordResult">
     <select id="selectSysKeywordById" resultMap="SysKeywordResult">
@@ -46,12 +59,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         insert into sys_keyword
         insert into sys_keyword
         <trim prefix="(" suffix=")" suffixOverrides=",">
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="keyword != null">keyword,</if>
             <if test="keyword != null">keyword,</if>
+            <if test="keywordType != null">keyword_type,</if>
+            <if test="keywordContent != null">keyword_content,</if>
+            <if test="remark != null">remark,</if>
             <if test="companyId != null">company_id,</if>
             <if test="companyId != null">company_id,</if>
             <if test="createTime != null">create_time,</if>
             <if test="createTime != null">create_time,</if>
             <if test="updateTime != null">update_time,</if>
             <if test="updateTime != null">update_time,</if>
          </trim>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="keyword != null">#{keyword},</if>
             <if test="keyword != null">#{keyword},</if>
+            <if test="keywordType != null">#{keywordType},</if>
+            <if test="keywordContent != null">#{keywordContent},</if>
+            <if test="remark != null">#{remark},</if>
             <if test="companyId != null">#{companyId},</if>
             <if test="companyId != null">#{companyId},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="updateTime != null">#{updateTime},</if>
             <if test="updateTime != null">#{updateTime},</if>
@@ -62,6 +81,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update sys_keyword
         update sys_keyword
         <trim prefix="SET" suffixOverrides=",">
         <trim prefix="SET" suffixOverrides=",">
             <if test="keyword != null">keyword = #{keyword},</if>
             <if test="keyword != null">keyword = #{keyword},</if>
+            <if test="keywordType != null">keyword_type = #{keywordType},</if>
+            <if test="keywordContent != null">keyword_content = #{keywordContent},</if>
+            <if test="remark != null">remark = #{remark},</if>
             <if test="companyId != null">company_id = #{companyId},</if>
             <if test="companyId != null">company_id = #{companyId},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>