Pārlūkot izejas kodu

店铺问答讨论优化:

dujian 3 mēneši atpakaļ
vecāks
revīzija
0c8fc8635d

+ 3 - 3
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformDiscussionController.java

@@ -98,11 +98,11 @@ public class StorePlatformDiscussionController {
         return R.data(storePlatformDiscussionService.listByStoreId(storeId, tags, sortMode));
     }
 
-    @ApiOperation("删除问答讨论")
+    @ApiOperation("撤消问答讨论")
     @DeleteMapping("/delete/{id}")
     public R<Boolean> delete(@PathVariable Integer id) {
         log.info("StorePlatformDiscussionController.delete?id={}", id);
-        boolean success = storePlatformDiscussionService.removeById(id);
-        return success ? R.success("删除成功") : R.fail("删除失败");
+        boolean success = storePlatformDiscussionService.deleteDiscussion(id);
+        return success ? R.success("撤消成功") : R.fail("撤消失败");
     }
 }

+ 37 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformDiscussionLike.java

@@ -0,0 +1,37 @@
+package shop.alien.storeplatform.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 店铺讨论点赞记录表
+ *
+ * @author alien
+ * @since 2025-12-30
+ */
+@Data
+@TableName("store_discussion_like")
+@ApiModel(value = "StorePlatformDiscussionLike对象", description = "店铺讨论点赞记录表")
+public class StorePlatformDiscussionLike {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "讨论ID")
+    @TableField("discussion_id")
+    private Integer discussionId;
+
+    @ApiModelProperty(value = "用户ID")
+    @TableField("user_id")
+    private Integer userId;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    private Date createdTime;
+}
+

+ 17 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformDiscussionLikeMapper.java

@@ -0,0 +1,17 @@
+package shop.alien.storeplatform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.storeplatform.entity.StorePlatformDiscussionLike;
+
+/**
+ * 店铺讨论点赞记录表 Mapper 接口
+ *
+ * @author alien
+ * @since 2025-12-30
+ */
+@Mapper
+public interface StorePlatformDiscussionLikeMapper extends BaseMapper<StorePlatformDiscussionLike> {
+
+}
+

+ 7 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformDiscussionService.java

@@ -67,4 +67,11 @@ public interface StorePlatformDiscussionService extends IService<StorePlatformDi
      * @return 是否成功
      */
     boolean likeDiscussion(Integer id);
+
+    /**
+     * 删除问答讨论
+     * @param id 讨论ID
+     * @return 是否成功
+     */
+    boolean deleteDiscussion(Integer id);
 }

+ 131 - 4
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformDiscussionServiceImpl.java

@@ -4,9 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.Data;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
@@ -14,8 +17,11 @@ import org.springframework.util.StringUtils;
 import shop.alien.entity.store.LifeUser;
 import shop.alien.mapper.LifeUserMapper;
 import shop.alien.storeplatform.entity.StorePlatformDiscussion;
+import shop.alien.storeplatform.entity.StorePlatformDiscussionLike;
+import shop.alien.storeplatform.mapper.StorePlatformDiscussionLikeMapper;
 import shop.alien.storeplatform.mapper.StorePlatformDiscussionMapper;
 import shop.alien.storeplatform.service.StorePlatformDiscussionService;
+import shop.alien.storeplatform.util.LoginUserUtil;
 import shop.alien.storeplatform.vo.StorePlatformDiscussionReplyVo;
 import shop.alien.storeplatform.vo.StorePlatformDiscussionUserVo;
 import shop.alien.util.common.safe.DeepseekClient;
@@ -35,8 +41,27 @@ import java.util.stream.Collectors;
 public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatformDiscussionMapper, StorePlatformDiscussion> implements StorePlatformDiscussionService {
 
     private final LifeUserMapper lifeUserMapper;
+    private final StorePlatformDiscussionLikeMapper discussionLikeMapper;
+    private final StoreDiscussionConfig discussionConfig;
     private final DeepseekClient deepseekClient = new DeepseekClient("sk-dd8a6e10972145c9847883791ac9fb41");
 
+    /**
+     * 内部配置类
+     */
+    @Data
+    @Component
+    @ConfigurationProperties(prefix = "alien.discussion")
+    public static class StoreDiscussionConfig {
+        /**
+         * 删除策略: 1-只删除当前讨论, 2-级联删除所有回复
+         * 默认为 2 (级联删除)
+         */
+        private Integer defaultDeleteStrategy = 2;
+
+        public static final int STRATEGY_SINGLE = 1;
+        public static final int STRATEGY_CASCADE = 2;
+    }
+
     @Override
     public IPage<StorePlatformDiscussionUserVo> pageRootDiscussions(Integer storeId, Integer pageNum, Integer pageSize, String tags, Integer sortMode) {
         LambdaQueryWrapper<StorePlatformDiscussion> wrapper = new LambdaQueryWrapper<StorePlatformDiscussion>()
@@ -139,10 +164,6 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
             String aiResponse = deepseekClient.generateText(prompt.toString());
             log.info("AI Ranking Response: {}", aiResponse);
 
-            // 解析 AI 响应并设置分数
-            // 注意:这里由于 deepseek 返回的是字符串,需要解析。简单处理演示:
-            // 实际上应该用正则或 JSON 解析库。
-            // 为了保证健壮性,这里假设解析成功。
             List<Map<String, Object>> scores = com.alibaba.fastjson.JSON.parseObject(aiResponse, new com.alibaba.fastjson.TypeReference<List<Map<String, Object>>>(){});
             Map<Integer, Double> scoreMap = scores.stream().collect(Collectors.toMap(
                     m -> (Integer) m.get("id"),
@@ -171,6 +192,7 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
         discussion.setLikeCount(0); // 初始化点赞数
         boolean saved = this.save(discussion);
         if (saved) {
+            // 一级讨论的 rootId 设置为它自己的 ID
             discussion.setRootId(discussion.getId());
             this.updateById(discussion);
         }
@@ -189,11 +211,14 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
             throw new RuntimeException("父级讨论不存在");
         }
         
+        // 从父级继承 storeId 和 rootId
         discussion.setStoreId(parent.getStoreId());
         discussion.setLikeCount(0); // 初始化点赞数
         if (parent.getParentId() == 0) {
+            // 如果父级是根讨论,那么 rootId 就是父级的 id
             discussion.setRootId(parent.getId());
         } else {
+            // 如果父级本身也是回复,那么 rootId 沿用父级的 rootId
             discussion.setRootId(parent.getRootId());
         }
         
@@ -201,10 +226,88 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean likeDiscussion(Integer id) {
+        Integer currentUserId = LoginUserUtil.getCurrentUserId();
+        if (currentUserId == null) {
+            throw new RuntimeException("请先登录再进行点赞");
+        }
+
+        // 检查是否已点赞
+        LambdaQueryWrapper<StorePlatformDiscussionLike> likeWrapper = new LambdaQueryWrapper<>();
+        likeWrapper.eq(StorePlatformDiscussionLike::getDiscussionId, id)
+                   .eq(StorePlatformDiscussionLike::getUserId, currentUserId);
+        
+        if (discussionLikeMapper.selectCount(likeWrapper) > 0) {
+            throw new RuntimeException("您已点赞过该内容");
+        }
+
+        // 插入点赞记录
+        StorePlatformDiscussionLike like = new StorePlatformDiscussionLike();
+        like.setDiscussionId(id);
+        like.setUserId(currentUserId);
+        discussionLikeMapper.insert(like);
+
+        // 更新点赞数
         return this.update().setSql("like_count = like_count + 1").eq("id", id).update();
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteDiscussion(Integer id) {
+        StorePlatformDiscussion discussion = this.getById(id);
+        if (discussion == null) {
+            return false;
+        }
+
+        // 使用配置中的默认策略
+        int finalStrategy = discussionConfig.getDefaultDeleteStrategy();
+
+        List<Integer> idsToDelete = new ArrayList<>();
+        idsToDelete.add(id);
+
+        if (finalStrategy == StoreDiscussionConfig.STRATEGY_CASCADE) {
+            // 级联删除策略
+            if (discussion.getParentId() == 0) {
+                // 如果是一级讨论,直接查找所有 rootId 等于该 id 的讨论(包括子回复)
+                List<StorePlatformDiscussion> allInRoot = this.list(new LambdaQueryWrapper<StorePlatformDiscussion>()
+                        .eq(StorePlatformDiscussion::getRootId, id));
+                idsToDelete.addAll(allInRoot.stream().map(StorePlatformDiscussion::getId).collect(Collectors.toList()));
+            } else {
+                // 如果是二级回复,需要通过递归找到所有子级回复
+                findAllDescendantIds(id, idsToDelete);
+            }
+        }
+
+        // 去重
+        Set<Integer> uniqueIds = new HashSet<>(idsToDelete);
+
+        // 1. 逻辑删除讨论
+        boolean removed = this.removeByIds(uniqueIds);
+
+        if (removed) {
+            // 2. 物理删除关联的点赞数据 (讨论删除了,点赞记录也应随之清除)
+            discussionLikeMapper.delete(new LambdaQueryWrapper<StorePlatformDiscussionLike>()
+                    .in(StorePlatformDiscussionLike::getDiscussionId, uniqueIds));
+        }
+
+        return removed;
+    }
+
+    /**
+     * 递归查找所有子级 ID (用于级联删除)
+     */
+    private void findAllDescendantIds(Integer parentId, List<Integer> resultList) {
+        List<StorePlatformDiscussion> children = this.list(new LambdaQueryWrapper<StorePlatformDiscussion>()
+                .eq(StorePlatformDiscussion::getParentId, parentId));
+        if (!CollectionUtils.isEmpty(children)) {
+            for (StorePlatformDiscussion child : children) {
+                resultList.add(child.getId());
+                findAllDescendantIds(child.getId(), resultList);
+            }
+        }
+    }
+
     private StorePlatformDiscussionUserVo convertToVo(StorePlatformDiscussion discussion) {
         if (discussion == null) return null;
         StorePlatformDiscussionUserVo vo = new StorePlatformDiscussionUserVo();
@@ -222,18 +325,41 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
         return vo;
     }
 
+    /**
+     * 批量填充用户信息和点赞状态
+     */
     private void fillUserInfoBatch(List<StorePlatformDiscussionUserVo> voList) {
         if (CollectionUtils.isEmpty(voList)) return;
 
+        // 提取所有用户ID和父级ID对应的人
         Set<Integer> userIds = voList.stream().map(StorePlatformDiscussionUserVo::getUserId).collect(Collectors.toSet());
+        
+        // 提取所有父级讨论,用于获取回复对象的名称
         Set<Integer> parentIds = voList.stream()
                 .map(StorePlatformDiscussionUserVo::getParentId)
                 .filter(id -> id != null && id != 0)
                 .collect(Collectors.toSet());
 
+        // 获取评论人信息
         Map<Integer, LifeUser> userMap = getUserMap(userIds);
+        
+        // 获取回复对象信息 (如果是回复,需要知道在回复谁)
         Map<Integer, String> parentUserNameMap = getParentUserNameMap(parentIds);
 
+        // 获取当前用户的点赞状态
+        Integer currentUserId = LoginUserUtil.getCurrentUserId();
+        Set<Integer> likedDiscussionIds = Collections.emptySet();
+        if (currentUserId != null) {
+            List<Integer> discussionIds = voList.stream().map(StorePlatformDiscussionUserVo::getId).collect(Collectors.toList());
+            likedDiscussionIds = discussionLikeMapper.selectList(new LambdaQueryWrapper<StorePlatformDiscussionLike>()
+                    .eq(StorePlatformDiscussionLike::getUserId, currentUserId)
+                    .in(StorePlatformDiscussionLike::getDiscussionId, discussionIds))
+                    .stream()
+                    .map(StorePlatformDiscussionLike::getDiscussionId)
+                    .collect(Collectors.toSet());
+        }
+
+        final Set<Integer> finalLikedIds = likedDiscussionIds;
         voList.forEach(vo -> {
             LifeUser user = userMap.get(vo.getUserId());
             if (user != null) {
@@ -243,6 +369,7 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
             if (vo.getParentId() != null && vo.getParentId() != 0) {
                 vo.setParentUserName(parentUserNameMap.get(vo.getParentId()));
             }
+            vo.setIsLiked(finalLikedIds.contains(vo.getId()) ? 1 : 0);
         });
     }
 

+ 3 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/vo/StorePlatformDiscussionUserVo.java

@@ -25,5 +25,8 @@ public class StorePlatformDiscussionUserVo extends StorePlatformDiscussion {
 
     @ApiModelProperty(value = "AI 相关性评分")
     private Double relevanceScore;
+
+    @ApiModelProperty(value = "当前用户是否已点赞 (0-未点赞, 1-已点赞)")
+    private Integer isLiked;
 }