|
@@ -4,9 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
|
|
+import lombok.Data;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
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.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
import org.springframework.util.CollectionUtils;
|
|
@@ -14,8 +17,11 @@ import org.springframework.util.StringUtils;
|
|
|
import shop.alien.entity.store.LifeUser;
|
|
import shop.alien.entity.store.LifeUser;
|
|
|
import shop.alien.mapper.LifeUserMapper;
|
|
import shop.alien.mapper.LifeUserMapper;
|
|
|
import shop.alien.storeplatform.entity.StorePlatformDiscussion;
|
|
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.mapper.StorePlatformDiscussionMapper;
|
|
|
import shop.alien.storeplatform.service.StorePlatformDiscussionService;
|
|
import shop.alien.storeplatform.service.StorePlatformDiscussionService;
|
|
|
|
|
+import shop.alien.storeplatform.util.LoginUserUtil;
|
|
|
import shop.alien.storeplatform.vo.StorePlatformDiscussionReplyVo;
|
|
import shop.alien.storeplatform.vo.StorePlatformDiscussionReplyVo;
|
|
|
import shop.alien.storeplatform.vo.StorePlatformDiscussionUserVo;
|
|
import shop.alien.storeplatform.vo.StorePlatformDiscussionUserVo;
|
|
|
import shop.alien.util.common.safe.DeepseekClient;
|
|
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 {
|
|
public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatformDiscussionMapper, StorePlatformDiscussion> implements StorePlatformDiscussionService {
|
|
|
|
|
|
|
|
private final LifeUserMapper lifeUserMapper;
|
|
private final LifeUserMapper lifeUserMapper;
|
|
|
|
|
+ private final StorePlatformDiscussionLikeMapper discussionLikeMapper;
|
|
|
|
|
+ private final StoreDiscussionConfig discussionConfig;
|
|
|
private final DeepseekClient deepseekClient = new DeepseekClient("sk-dd8a6e10972145c9847883791ac9fb41");
|
|
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
|
|
@Override
|
|
|
public IPage<StorePlatformDiscussionUserVo> pageRootDiscussions(Integer storeId, Integer pageNum, Integer pageSize, String tags, Integer sortMode) {
|
|
public IPage<StorePlatformDiscussionUserVo> pageRootDiscussions(Integer storeId, Integer pageNum, Integer pageSize, String tags, Integer sortMode) {
|
|
|
LambdaQueryWrapper<StorePlatformDiscussion> wrapper = new LambdaQueryWrapper<StorePlatformDiscussion>()
|
|
LambdaQueryWrapper<StorePlatformDiscussion> wrapper = new LambdaQueryWrapper<StorePlatformDiscussion>()
|
|
@@ -139,10 +164,6 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
|
|
|
String aiResponse = deepseekClient.generateText(prompt.toString());
|
|
String aiResponse = deepseekClient.generateText(prompt.toString());
|
|
|
log.info("AI Ranking Response: {}", aiResponse);
|
|
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>>>(){});
|
|
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(
|
|
Map<Integer, Double> scoreMap = scores.stream().collect(Collectors.toMap(
|
|
|
m -> (Integer) m.get("id"),
|
|
m -> (Integer) m.get("id"),
|
|
@@ -171,6 +192,7 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
|
|
|
discussion.setLikeCount(0); // 初始化点赞数
|
|
discussion.setLikeCount(0); // 初始化点赞数
|
|
|
boolean saved = this.save(discussion);
|
|
boolean saved = this.save(discussion);
|
|
|
if (saved) {
|
|
if (saved) {
|
|
|
|
|
+ // 一级讨论的 rootId 设置为它自己的 ID
|
|
|
discussion.setRootId(discussion.getId());
|
|
discussion.setRootId(discussion.getId());
|
|
|
this.updateById(discussion);
|
|
this.updateById(discussion);
|
|
|
}
|
|
}
|
|
@@ -189,11 +211,14 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
|
|
|
throw new RuntimeException("父级讨论不存在");
|
|
throw new RuntimeException("父级讨论不存在");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 从父级继承 storeId 和 rootId
|
|
|
discussion.setStoreId(parent.getStoreId());
|
|
discussion.setStoreId(parent.getStoreId());
|
|
|
discussion.setLikeCount(0); // 初始化点赞数
|
|
discussion.setLikeCount(0); // 初始化点赞数
|
|
|
if (parent.getParentId() == 0) {
|
|
if (parent.getParentId() == 0) {
|
|
|
|
|
+ // 如果父级是根讨论,那么 rootId 就是父级的 id
|
|
|
discussion.setRootId(parent.getId());
|
|
discussion.setRootId(parent.getId());
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ // 如果父级本身也是回复,那么 rootId 沿用父级的 rootId
|
|
|
discussion.setRootId(parent.getRootId());
|
|
discussion.setRootId(parent.getRootId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -201,10 +226,88 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
public boolean likeDiscussion(Integer id) {
|
|
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();
|
|
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) {
|
|
private StorePlatformDiscussionUserVo convertToVo(StorePlatformDiscussion discussion) {
|
|
|
if (discussion == null) return null;
|
|
if (discussion == null) return null;
|
|
|
StorePlatformDiscussionUserVo vo = new StorePlatformDiscussionUserVo();
|
|
StorePlatformDiscussionUserVo vo = new StorePlatformDiscussionUserVo();
|
|
@@ -222,18 +325,41 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
|
|
|
return vo;
|
|
return vo;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 批量填充用户信息和点赞状态
|
|
|
|
|
+ */
|
|
|
private void fillUserInfoBatch(List<StorePlatformDiscussionUserVo> voList) {
|
|
private void fillUserInfoBatch(List<StorePlatformDiscussionUserVo> voList) {
|
|
|
if (CollectionUtils.isEmpty(voList)) return;
|
|
if (CollectionUtils.isEmpty(voList)) return;
|
|
|
|
|
|
|
|
|
|
+ // 提取所有用户ID和父级ID对应的人
|
|
|
Set<Integer> userIds = voList.stream().map(StorePlatformDiscussionUserVo::getUserId).collect(Collectors.toSet());
|
|
Set<Integer> userIds = voList.stream().map(StorePlatformDiscussionUserVo::getUserId).collect(Collectors.toSet());
|
|
|
|
|
+
|
|
|
|
|
+ // 提取所有父级讨论,用于获取回复对象的名称
|
|
|
Set<Integer> parentIds = voList.stream()
|
|
Set<Integer> parentIds = voList.stream()
|
|
|
.map(StorePlatformDiscussionUserVo::getParentId)
|
|
.map(StorePlatformDiscussionUserVo::getParentId)
|
|
|
.filter(id -> id != null && id != 0)
|
|
.filter(id -> id != null && id != 0)
|
|
|
.collect(Collectors.toSet());
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
+ // 获取评论人信息
|
|
|
Map<Integer, LifeUser> userMap = getUserMap(userIds);
|
|
Map<Integer, LifeUser> userMap = getUserMap(userIds);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取回复对象信息 (如果是回复,需要知道在回复谁)
|
|
|
Map<Integer, String> parentUserNameMap = getParentUserNameMap(parentIds);
|
|
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 -> {
|
|
voList.forEach(vo -> {
|
|
|
LifeUser user = userMap.get(vo.getUserId());
|
|
LifeUser user = userMap.get(vo.getUserId());
|
|
|
if (user != null) {
|
|
if (user != null) {
|
|
@@ -243,6 +369,7 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
|
|
|
if (vo.getParentId() != null && vo.getParentId() != 0) {
|
|
if (vo.getParentId() != null && vo.getParentId() != 0) {
|
|
|
vo.setParentUserName(parentUserNameMap.get(vo.getParentId()));
|
|
vo.setParentUserName(parentUserNameMap.get(vo.getParentId()));
|
|
|
}
|
|
}
|
|
|
|
|
+ vo.setIsLiked(finalLikedIds.contains(vo.getId()) ? 1 : 0);
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|