From b11a3463b23ebdae336d8f9255a8bdc84c964bea Mon Sep 17 00:00:00 2001 From: Peanut Date: Sun, 28 Jun 2026 17:42:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=89=A7=E6=9C=AC?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=89=88=E6=9C=AC=E7=AE=A1=E7=90=86=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../impl/ScriptMessageServiceImpl.java | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 server/src/main/java/com/emotion/service/impl/ScriptMessageServiceImpl.java diff --git a/server/src/main/java/com/emotion/service/impl/ScriptMessageServiceImpl.java b/server/src/main/java/com/emotion/service/impl/ScriptMessageServiceImpl.java new file mode 100644 index 0000000..9e78097 --- /dev/null +++ b/server/src/main/java/com/emotion/service/impl/ScriptMessageServiceImpl.java @@ -0,0 +1,144 @@ +package com.emotion.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.emotion.dto.response.MessageResponse; +import com.emotion.entity.Conversation; +import com.emotion.entity.EpicScript; +import com.emotion.entity.Message; +import com.emotion.service.ConversationService; +import com.emotion.service.EpicScriptService; +import com.emotion.service.MessageService; +import com.emotion.service.ScriptMessageService; +import com.emotion.util.UserContextHolder; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 剧本消息版本管理服务实现 + */ +@Service +public class ScriptMessageServiceImpl implements ScriptMessageService { + + @Autowired + private MessageService messageService; + + @Autowired + private ConversationService conversationService; + + @Autowired + private EpicScriptService epicScriptService; + + @Override + public List listByConversation(String conversationId, boolean includeVersions) { + String currentUserId = UserContextHolder.getCurrentUserId(); + Conversation conversation = conversationService.getById(conversationId); + if (conversation == null || !conversation.getUserId().equals(currentUserId)) { + throw new IllegalStateException("对话不存在或无权限"); + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Message::getConversationId, conversationId); + if (!includeVersions) { + // 只返回当前生效版本链上的消息:parent_message_id 为空的 script 消息 + 所有 chat 消息 + wrapper.and(w -> w.isNull(Message::getParentMessageId).or().ne(Message::getType, "script")); + } + wrapper.orderByAsc(Message::getMessageOrder); + List messages = messageService.list(wrapper); + return messages.stream().map(this::convertToResponse).collect(Collectors.toList()); + } + + @Override + public List getVersions(String messageId) { + String currentUserId = UserContextHolder.getCurrentUserId(); + Message message = messageService.getById(messageId); + if (message == null) { + throw new IllegalStateException("消息不存在"); + } + Conversation conversation = conversationService.getById(message.getConversationId()); + if (conversation == null || !conversation.getUserId().equals(currentUserId)) { + throw new IllegalStateException("无权限"); + } + + // 找到根消息 + String rootId = message.getParentMessageId() == null ? message.getId() : message.getParentMessageId(); + Message root = messageService.getById(rootId); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Message::getParentMessageId, rootId) + .orderByAsc(Message::getVersionNumber); + List versions = messageService.list(wrapper); + + List result = new ArrayList<>(); + if (root != null) { + result.add(convertToResponse(root)); + } + result.addAll(versions.stream().map(this::convertToResponse).collect(Collectors.toList())); + return result; + } + + @Override + public boolean deleteVersion(String messageId) { + String currentUserId = UserContextHolder.getCurrentUserId(); + Message message = messageService.getById(messageId); + if (message == null) { + throw new IllegalStateException("消息不存在"); + } + Conversation conversation = conversationService.getById(message.getConversationId()); + if (conversation == null || !conversation.getUserId().equals(currentUserId)) { + throw new IllegalStateException("无权限"); + } + + EpicScript script = epicScriptService.getById(conversation.getScriptId()); + if (script == null) { + throw new IllegalStateException("剧本不存在"); + } + + // 不能删除当前生效版本 + if (messageId.equals(script.getCurrentVersionMessageId())) { + throw new IllegalStateException("不能删除当前生效版本"); + } + + // 不能删除有子版本的父消息 + if (message.getParentMessageId() == null) { + LambdaQueryWrapper childWrapper = new LambdaQueryWrapper<>(); + childWrapper.eq(Message::getParentMessageId, messageId); + long childCount = messageService.count(childWrapper); + if (childCount > 0) { + throw new IllegalStateException("不能删除有子版本的父消息"); + } + } + + String parentId = message.getParentMessageId(); + boolean removed = messageService.removeById(messageId); + if (!removed) { + return false; + } + + // 重新计算同一 parent 下剩余版本的 version_number + if (StringUtils.hasText(parentId)) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Message::getParentMessageId, parentId) + .orderByAsc(Message::getMessageOrder); + List siblings = messageService.list(wrapper); + for (int i = 0; i < siblings.size(); i++) { + Message sibling = siblings.get(i); + sibling.setVersionNumber(i + 2); + messageService.updateById(sibling); + } + } + return true; + } + + private MessageResponse convertToResponse(Message message) { + MessageResponse response = new MessageResponse(); + BeanUtils.copyProperties(message, response); + response.setId(message.getId()); + return response; + } +} \ No newline at end of file