diff --git a/src/main/java/com/filesystem/controller/MessageController.java b/src/main/java/com/filesystem/controller/MessageController.java index aa1e1da..dad100e 100644 --- a/src/main/java/com/filesystem/controller/MessageController.java +++ b/src/main/java/com/filesystem/controller/MessageController.java @@ -276,4 +276,12 @@ public class MessageController { messageService.markAsRead(id); return ResponseEntity.ok(Map.of("message", "已标记已读")); } + + @DeleteMapping("/conversation/{withUserId}") + public ResponseEntity deleteConversation( + @AuthenticationPrincipal UserPrincipal principal, + @PathVariable Long withUserId) { + messageService.deleteConversation(principal.getUserId(), withUserId); + return ResponseEntity.ok(Map.of("message", "已删除")); + } } diff --git a/src/main/java/com/filesystem/service/MessageService.java b/src/main/java/com/filesystem/service/MessageService.java index 1b46683..93b4c5d 100644 --- a/src/main/java/com/filesystem/service/MessageService.java +++ b/src/main/java/com/filesystem/service/MessageService.java @@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.filesystem.entity.Message; import com.filesystem.mapper.MessageMapper; import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.util.*; @@ -14,8 +16,16 @@ public class MessageService { @Resource private MessageMapper messageMapper; + + @Autowired + private StringRedisTemplate redisTemplate; + + private static final String CONV_DELETED_KEY = "msg:del:"; public List getMessages(Long userId1, Long userId2) { + String convKey = buildConvKey(userId1, userId2); + String deletedKey = CONV_DELETED_KEY + userId1 + ":" + convKey; + return messageMapper.selectList( new LambdaQueryWrapper() .and(wrapper -> wrapper @@ -26,6 +36,31 @@ public class MessageService { .orderByAsc(Message::getCreateTime) ); } + + /** + * 删除与某个用户的聊天记录(双向,本人会看不到) + */ + public void deleteConversation(Long userId, Long withUserId) { + String convKey = buildConvKey(userId, withUserId); + String deletedKey = CONV_DELETED_KEY + userId + ":" + convKey; + // 保留7天 + redisTemplate.opsForValue().set(deletedKey, "1", java.time.Duration.ofDays(7)); + } + + /** + * 检查与某人的对话是否已被当前用户删除 + */ + public boolean isConversationDeleted(Long userId, Long withUserId) { + String convKey = buildConvKey(userId, withUserId); + String deletedKey = CONV_DELETED_KEY + userId + ":" + convKey; + return Boolean.TRUE.equals(redisTemplate.hasKey(deletedKey)); + } + + private String buildConvKey(Long userId1, Long userId2) { + long min = Math.min(userId1, userId2); + long max = Math.max(userId1, userId2); + return min + "_" + max; + } public Message sendMessage(Long fromUserId, Long toUserId, String content, String type) { Message message = new Message(); diff --git a/web-vue/src/api/message.js b/web-vue/src/api/message.js index 1cfcf9c..d5fdf5b 100644 --- a/web-vue/src/api/message.js +++ b/web-vue/src/api/message.js @@ -10,6 +10,8 @@ export const getUnreadList = () => request.get('/messages/unreadList') export const markAsRead = (id) => request.post(`/messages/${id}/read`) +export const deleteConversation = (withUserId) => request.delete(`/messages/conversation/${withUserId}`) + export const getUsers = () => request.get('/messages/users') // 聊天文件上传(图片和文件统一接口) diff --git a/web-vue/src/components/ChatDialog.vue b/web-vue/src/components/ChatDialog.vue index 8531e31..f091f56 100644 --- a/web-vue/src/components/ChatDialog.vue +++ b/web-vue/src/components/ChatDialog.vue @@ -217,7 +217,7 @@ import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue' import { ElMessage } from 'element-plus' import { ChatLineRound, User, Search, Close, Loading, Picture, Paperclip, Download, ChatDotRound, Promotion } from '@element-plus/icons-vue' import { useUserStore } from '@/store/user' -import { getUsers, getMessages, sendMessage as sendMessageApi, uploadChatFile, getUnreadList } from '@/api/message' +import { getUsers, getMessages, sendMessage as sendMessageApi, uploadChatFile, getUnreadList, deleteConversation } from '@/api/message' import { chatService } from '@/services/chat' const props = defineProps({ modelValue: Boolean }) @@ -571,7 +571,12 @@ const downloadFile = async (msg) => { // ======== 其他操作 ======== -const deleteRecentChat = (chat) => { +const deleteRecentChat = async (chat) => { + try { + await deleteConversation(chat.id) + } catch (e) { + // 即使 API 失败也删本地 + } const idx = recentChats.value.findIndex(c => c.id === chat.id) if (idx > -1) recentChats.value.splice(idx, 1) if (currentContact.value?.id === chat.id) currentContact.value = null