diff --git a/backend/IM_API/Configs/ServiceCollectionExtensions.cs b/backend/IM_API/Configs/ServiceCollectionExtensions.cs index bbb43c4..f811e2e 100644 --- a/backend/IM_API/Configs/ServiceCollectionExtensions.cs +++ b/backend/IM_API/Configs/ServiceCollectionExtensions.cs @@ -12,6 +12,7 @@ namespace IM_API.Configs services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddSingleton(); services.AddSingleton(); return services; diff --git a/backend/IM_API/Controllers/ConversationController.cs b/backend/IM_API/Controllers/ConversationController.cs new file mode 100644 index 0000000..77db965 --- /dev/null +++ b/backend/IM_API/Controllers/ConversationController.cs @@ -0,0 +1,33 @@ +using IM_API.Dtos; +using IM_API.Interface.Services; +using IM_API.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace IM_API.Controllers +{ + [Route("api/[controller]/[action]")] + [Authorize] + [ApiController] + public class ConversationController : ControllerBase + { + private readonly IConversationService _conversationSerivice; + private readonly ILogger _logger; + public ConversationController(IConversationService conversationSerivice, ILogger logger) + { + _conversationSerivice = conversationSerivice; + _logger = logger; + } + [HttpGet] + public async Task List() + { + var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier); + var list = await _conversationSerivice.GetConversationsAsync(int.Parse(userIdStr)); + var res = new BaseResponse>(list); + return Ok(res); + } + + } +} diff --git a/backend/IM_API/Interface/Services/IConversationService.cs b/backend/IM_API/Interface/Services/IConversationService.cs index 9c4bf63..3f2aa5a 100644 --- a/backend/IM_API/Interface/Services/IConversationService.cs +++ b/backend/IM_API/Interface/Services/IConversationService.cs @@ -10,12 +10,18 @@ namespace IM_API.Interface.Services /// /// /// - Task ClearConversationsAsync(ClearConversationsDto clearConversationsDto); + Task ClearConversationsAsync(int userId); + /// + /// 删除单个聊天会话 + /// + /// + /// + Task DeleteConversationAsync(int conversationId); /// /// 获取用户当前消息会话 /// /// 用户id /// - Task GetConversationsAsync(int userId); + Task> GetConversationsAsync(int userId); } } diff --git a/backend/IM_API/Services/ConversationService.cs b/backend/IM_API/Services/ConversationService.cs new file mode 100644 index 0000000..56632a1 --- /dev/null +++ b/backend/IM_API/Services/ConversationService.cs @@ -0,0 +1,44 @@ +using IM_API.Dtos; +using IM_API.Exceptions; +using IM_API.Interface.Services; +using IM_API.Models; +using IM_API.Tools; +using Microsoft.EntityFrameworkCore; + +namespace IM_API.Services +{ + public class ConversationService : IConversationService + { + private readonly ImContext _context; + public ConversationService(ImContext context) + { + _context = context; + } + #region 删除用户会话 + public async Task ClearConversationsAsync(int userId) + { + await _context.Conversations.Where(x => x.UserId == userId).ExecuteDeleteAsync(); + return true; + } + + + #endregion + #region 获取用户会话列表 + public async Task> GetConversationsAsync(int userId) + { + return await _context.Conversations.Where(x => x.UserId == userId) + .ToListAsync(); + } + #endregion + #region 删除单个会话 + public async Task DeleteConversationAsync(int conversationId) + { + var conversation = await _context.Conversations.FirstOrDefaultAsync(x => x.Id == conversationId); + if (conversation == null) throw new BaseException(CodeDefine.CONVERSATION_NOT_FOUND); + _context.Conversations.Remove(conversation); + await _context.SaveChangesAsync(); + return true; + } + #endregion + } +} \ No newline at end of file diff --git a/backend/IM_API/Services/FriendService.cs b/backend/IM_API/Services/FriendService.cs index 6576b36..e5ef1f1 100644 --- a/backend/IM_API/Services/FriendService.cs +++ b/backend/IM_API/Services/FriendService.cs @@ -68,7 +68,7 @@ namespace IM_API.Services { query = query.OrderByDescending(x => x.UserId); } - var friendList = await query.Skip((page - 1 * limit)).Take(limit).ToListAsync(); + var friendList = await query.Skip(((page - 1) * limit)).Take(limit).ToListAsync(); return _mapper.Map>(friendList); } #endregion diff --git a/backend/IM_API/Services/MessageService.cs b/backend/IM_API/Services/MessageService.cs index d3e8b16..223c775 100644 --- a/backend/IM_API/Services/MessageService.cs +++ b/backend/IM_API/Services/MessageService.cs @@ -54,12 +54,24 @@ namespace IM_API.Services { throw new NotImplementedException(); } - - public Task SendGroupMessageAsync(int senderId, int groupId, MessageBaseDto dto) + #region 发送群消息 + public async Task SendGroupMessageAsync(int senderId, int groupId, MessageBaseDto dto) { - throw new NotImplementedException(); - } + //判断群存在 + var isExist = await _context.Groups.AnyAsync(x => x.Id == groupId); + if (!isExist) throw new BaseException(CodeDefine.GROUP_NOT_FOUND); + //判断是否是群成员 + var isMember = await _context.GroupMembers.AnyAsync(x => x.GroupId == groupId && x.UserId == senderId); + if (!isMember) throw new BaseException(CodeDefine.NO_GROUP_PERMISSION); + var message = _mapper.Map(dto); + message.Sender = senderId; + _context.Messages.Add(message); + await _context.SaveChangesAsync(); + return true; + } + #endregion + #region 发送私聊消息 public async Task SendPrivateMessageAsync(int senderId, int receiverId, MessageBaseDto dto) { bool isExist = await _context.Friends.AnyAsync(x => x.FriendId == receiverId); @@ -70,5 +82,6 @@ namespace IM_API.Services await _context.SaveChangesAsync(); return true; } + #endregion } } diff --git a/backend/IM_API/Tools/CodeDefine.cs b/backend/IM_API/Tools/CodeDefine.cs index 5733b58..e62989e 100644 --- a/backend/IM_API/Tools/CodeDefine.cs +++ b/backend/IM_API/Tools/CodeDefine.cs @@ -102,5 +102,8 @@ /// 后台日志写入失败 public static CodeDefine OPERATION_LOG_FAILED = new CodeDefine(3004, "操作记录失败"); + // 3.9 会话相关错误(3100 ~ 3199) + /// 发送时异常 + public static CodeDefine CONVERSATION_NOT_FOUND = new CodeDefine(3100, "会话不存在"); } } diff --git a/frontend/web/.env b/frontend/web/.env index ba350c4..b61e7b0 100644 --- a/frontend/web/.env +++ b/frontend/web/.env @@ -1 +1 @@ -VITE_API_BASE_URL = http://192.168.5.116:7070/api \ No newline at end of file +VITE_API_BASE_URL = http://localhost:5202/api \ No newline at end of file diff --git a/frontend/web/src/services/api.js b/frontend/web/src/services/api.js index a1fa558..dc5fd77 100644 --- a/frontend/web/src/services/api.js +++ b/frontend/web/src/services/api.js @@ -1,8 +1,10 @@ import axios from 'axios' import { useMessage } from '@/components/messages/useAlert'; import router from '@/router'; +import { useAuthStore } from '@/stores/auth'; -const message = useMessage() +const message = useMessage(); +const authStore = useAuthStore(); const api = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api', // 从环境变量中读取基础 URL @@ -14,7 +16,7 @@ const api = axios.create({ api.interceptors.request.use( config => { - const token = localStorage.getItem('authToken'); + const token = authStore.token; if (token) { config.headers.Authorization = `Bearer ${token}`; } diff --git a/frontend/web/src/services/friend.js b/frontend/web/src/services/friend.js new file mode 100644 index 0000000..c4dc0f2 --- /dev/null +++ b/frontend/web/src/services/friend.js @@ -0,0 +1,14 @@ +import { request } from "./api"; + +export const friendService = { + + /** + * 获取好友列表 + * @param {*} page 当前页 + * @param {*} limit 页大小 + * @returns + */ + getFriendList: (page = 1, limit = 100) => request.get(`/friend/list?page=${page}&limit=${limit}`) + + +} \ No newline at end of file diff --git a/frontend/web/src/views/contact/ContactList.vue b/frontend/web/src/views/contact/ContactList.vue index 101df6f..8a09534 100644 --- a/frontend/web/src/views/contact/ContactList.vue +++ b/frontend/web/src/views/contact/ContactList.vue @@ -84,11 +84,14 @@