xiangyixiangqin/server/src/XiangYi.AppApi/Controllers/ChatController.cs
2026-01-28 19:42:20 +08:00

375 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using XiangYi.AppApi.Hubs;
using XiangYi.Application.DTOs.Requests;
using XiangYi.Application.DTOs.Responses;
using XiangYi.Application.Interfaces;
using XiangYi.Core.Constants;
using System.Security.Claims;
namespace XiangYi.AppApi.Controllers;
/// <summary>
/// 聊天控制器
/// </summary>
[ApiController]
[Route("api/app/chat")]
[Authorize]
public class ChatController : ControllerBase
{
private readonly IChatService _chatService;
private readonly IHubContext<ChatHub> _hubContext;
private readonly ILogger<ChatController> _logger;
public ChatController(
IChatService chatService,
IHubContext<ChatHub> hubContext,
ILogger<ChatController> logger)
{
_chatService = chatService;
_hubContext = hubContext;
_logger = logger;
}
/// <summary>
/// 获取会话列表
/// </summary>
/// <returns>会话列表</returns>
[HttpGet("sessions")]
public async Task<ApiResponse<List<ChatSessionResponse>>> GetSessions()
{
var userId = GetCurrentUserId();
var result = await _chatService.GetSessionsAsync(userId);
return ApiResponse<List<ChatSessionResponse>>.Success(result);
}
/// <summary>
/// 获取消息列表
/// </summary>
/// <param name="sessionId">会话ID</param>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页数量</param>
/// <returns>消息列表</returns>
[HttpGet("messages")]
public async Task<ApiResponse<PagedResult<ChatMessageResponse>>> GetMessages(
[FromQuery] long sessionId,
[FromQuery] int pageIndex = 1,
[FromQuery] int pageSize = 20)
{
if (sessionId <= 0)
{
return ApiResponse<PagedResult<ChatMessageResponse>>.Error(ErrorCodes.InvalidParameter, "会话ID无效");
}
var userId = GetCurrentUserId();
// 检查是否有权限访问会话
var canAccess = await _chatService.CanAccessSessionAsync(userId, sessionId);
if (!canAccess)
{
return ApiResponse<PagedResult<ChatMessageResponse>>.Error(ErrorCodes.Forbidden, "无权访问该会话");
}
var request = new GetMessagesRequest
{
SessionId = sessionId,
PageIndex = pageIndex,
PageSize = pageSize
};
var result = await _chatService.GetMessagesAsync(userId, request);
// 标记消息已读
await _chatService.MarkMessagesAsReadAsync(userId, sessionId);
return ApiResponse<PagedResult<ChatMessageResponse>>.Success(result);
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="request">发送消息请求</param>
/// <returns>发送结果</returns>
[HttpPost("send")]
public async Task<ApiResponse<SendMessageResponse>> SendMessage([FromBody] SendMessageRequest request)
{
if (request.SessionId <= 0)
{
return ApiResponse<SendMessageResponse>.Error(ErrorCodes.InvalidParameter, "会话ID无效");
}
if (request.ReceiverId <= 0)
{
return ApiResponse<SendMessageResponse>.Error(ErrorCodes.InvalidParameter, "接收者ID无效");
}
var userId = GetCurrentUserId();
// 检查是否有权限访问会话
var canAccess = await _chatService.CanAccessSessionAsync(userId, request.SessionId);
if (!canAccess)
{
return ApiResponse<SendMessageResponse>.Error(ErrorCodes.Forbidden, "无权访问该会话");
}
var result = await _chatService.SendMessageAsync(userId, request);
// 通过 SignalR 推送消息给会话中的所有用户
var messageResponse = new ChatMessageResponse
{
MessageId = result.MessageId,
SessionId = request.SessionId,
SenderId = userId,
ReceiverId = request.ReceiverId,
MessageType = request.MessageType,
Content = request.Content,
VoiceUrl = request.VoiceUrl,
VoiceDuration = request.VoiceDuration,
IsRead = false,
CreateTime = result.CreateTime,
IsSelf = false // 接收者收到时不是自己发的
};
// 推送给会话组(双方都能收到)
await _hubContext.SendMessageToSessionAsync(request.SessionId, messageResponse);
_logger.LogInformation("消息已通过SignalR推送到会话组: MessageId={MessageId}, SessionId={SessionId}",
result.MessageId, request.SessionId);
return ApiResponse<SendMessageResponse>.Success(result);
}
/// <summary>
/// 请求交换微信
/// </summary>
/// <param name="request">交换微信请求</param>
/// <returns>交换请求结果</returns>
[HttpPost("exchangeWeChat")]
public async Task<ApiResponse<ExchangeRequestResponse>> ExchangeWeChat([FromBody] ExchangeWeChatRequest request)
{
if (request.SessionId <= 0)
{
return ApiResponse<ExchangeRequestResponse>.Error(ErrorCodes.InvalidParameter, "会话ID无效");
}
if (request.ReceiverId <= 0)
{
return ApiResponse<ExchangeRequestResponse>.Error(ErrorCodes.InvalidParameter, "接收者ID无效");
}
var userId = GetCurrentUserId();
// 检查是否有权限访问会话
var canAccess = await _chatService.CanAccessSessionAsync(userId, request.SessionId);
if (!canAccess)
{
return ApiResponse<ExchangeRequestResponse>.Error(ErrorCodes.Forbidden, "无权访问该会话");
}
var result = await _chatService.ExchangeWeChatAsync(userId, request);
// 通过 SignalR 推送交换请求给会话组
var messageResponse = new ChatMessageResponse
{
MessageId = result.RequestMessageId,
SessionId = request.SessionId,
SenderId = userId,
ReceiverId = request.ReceiverId,
MessageType = 4, // ExchangeWeChatRequest
Content = "请求交换微信",
IsRead = false,
CreateTime = result.CreateTime,
IsSelf = false
};
await _hubContext.SendMessageToSessionAsync(request.SessionId, messageResponse);
_logger.LogInformation("交换微信请求已通过SignalR推送到会话组: MessageId={MessageId}, SessionId={SessionId}",
result.RequestMessageId, request.SessionId);
return ApiResponse<ExchangeRequestResponse>.Success(result);
}
/// <summary>
/// 请求交换照片
/// </summary>
/// <param name="request">交换照片请求</param>
/// <returns>交换请求结果</returns>
[HttpPost("exchangePhoto")]
public async Task<ApiResponse<ExchangeRequestResponse>> ExchangePhoto([FromBody] ExchangePhotoRequest request)
{
if (request.SessionId <= 0)
{
return ApiResponse<ExchangeRequestResponse>.Error(ErrorCodes.InvalidParameter, "会话ID无效");
}
if (request.ReceiverId <= 0)
{
return ApiResponse<ExchangeRequestResponse>.Error(ErrorCodes.InvalidParameter, "接收者ID无效");
}
var userId = GetCurrentUserId();
// 检查是否有权限访问会话
var canAccess = await _chatService.CanAccessSessionAsync(userId, request.SessionId);
if (!canAccess)
{
return ApiResponse<ExchangeRequestResponse>.Error(ErrorCodes.Forbidden, "无权访问该会话");
}
var result = await _chatService.ExchangePhotoAsync(userId, request);
// 通过 SignalR 推送交换请求给会话组
var messageResponse = new ChatMessageResponse
{
MessageId = result.RequestMessageId,
SessionId = request.SessionId,
SenderId = userId,
ReceiverId = request.ReceiverId,
MessageType = 6, // ExchangePhotoRequest
Content = "请求交换照片",
IsRead = false,
CreateTime = result.CreateTime,
IsSelf = false
};
await _hubContext.SendMessageToSessionAsync(request.SessionId, messageResponse);
_logger.LogInformation("交换照片请求已通过SignalR推送到会话组: MessageId={MessageId}, SessionId={SessionId}",
result.RequestMessageId, request.SessionId);
return ApiResponse<ExchangeRequestResponse>.Success(result);
}
/// <summary>
/// 响应交换请求
/// </summary>
/// <param name="request">响应请求</param>
/// <returns>响应结果</returns>
[HttpPost("respondExchange")]
public async Task<ApiResponse<ExchangeRespondResponse>> RespondExchange([FromBody] RespondExchangeRequest request)
{
if (request.RequestMessageId <= 0)
{
return ApiResponse<ExchangeRespondResponse>.Error(ErrorCodes.InvalidParameter, "请求消息ID无效");
}
var userId = GetCurrentUserId();
var result = await _chatService.RespondExchangeAsync(userId, request);
// 通过 SignalR 推送交换响应结果给会话组(双方都能收到)
var resultMessageType = result.RequestMessageType == 4 ? 5 : 7; // 4=ExchangeWeChatRequest->5=Result, 6=ExchangePhotoRequest->7=Result
// 构建 ExtraData确保始终包含 RequestMessageId即使拒绝时也需要
var extraDataForPush = result.ExchangedData;
if (string.IsNullOrEmpty(extraDataForPush))
{
// 拒绝时 ExchangedData 为空,需要手动构建包含 RequestMessageId 的数据
extraDataForPush = System.Text.Json.JsonSerializer.Serialize(new
{
RequestMessageId = result.RequestMessageId,
Status = result.IsAgreed ? 1 : 2
});
}
var messageResponse = new ChatMessageResponse
{
MessageId = result.ResultMessageId,
SessionId = result.SessionId,
SenderId = userId,
ReceiverId = result.RequesterId,
MessageType = resultMessageType,
Content = result.IsAgreed ? "已同意交换" : "已拒绝交换",
ExtraData = extraDataForPush,
IsRead = false,
CreateTime = DateTime.Now,
IsSelf = false
};
await _hubContext.SendMessageToSessionAsync(result.SessionId, messageResponse);
_logger.LogInformation("交换响应已通过SignalR推送到会话组: ResultMessageId={ResultMessageId}, SessionId={SessionId}, IsAgreed={IsAgreed}",
result.ResultMessageId, result.SessionId, result.IsAgreed);
return ApiResponse<ExchangeRespondResponse>.Success(result);
}
/// <summary>
/// 获取未读消息数
/// </summary>
/// <returns>未读消息数</returns>
[HttpGet("unreadCount")]
public async Task<ApiResponse<int>> GetUnreadCount()
{
var userId = GetCurrentUserId();
var count = await _chatService.GetUnreadCountAsync(userId);
return ApiResponse<int>.Success(count);
}
/// <summary>
/// 获取或创建会话
/// </summary>
/// <param name="targetUserId">目标用户ID</param>
/// <returns>会话ID</returns>
[HttpGet("session")]
public async Task<ApiResponse<long>> GetOrCreateSession([FromQuery] long targetUserId)
{
if (targetUserId <= 0)
{
return ApiResponse<long>.Error(ErrorCodes.InvalidParameter, "目标用户ID无效");
}
var userId = GetCurrentUserId();
if (userId == targetUserId)
{
return ApiResponse<long>.Error(ErrorCodes.InvalidParameter, "不能与自己创建会话");
}
var sessionId = await _chatService.GetOrCreateSessionAsync(userId, targetUserId);
return ApiResponse<long>.Success(sessionId);
}
/// <summary>
/// 删除会话
/// </summary>
/// <param name="request">删除会话请求</param>
/// <returns>删除结果</returns>
[HttpPost("session/delete")]
public async Task<ApiResponse> DeleteSession([FromBody] DeleteSessionRequest request)
{
if (request.SessionId <= 0)
{
return ApiResponse.Error(ErrorCodes.InvalidParameter, "会话ID无效");
}
var userId = GetCurrentUserId();
// 检查是否有权限访问会话
var canAccess = await _chatService.CanAccessSessionAsync(userId, request.SessionId);
if (!canAccess)
{
return ApiResponse.Error(ErrorCodes.Forbidden, "无权访问该会话");
}
await _chatService.DeleteSessionAsync(userId, request.SessionId);
return ApiResponse.Success("删除成功");
}
/// <summary>
/// 获取当前用户ID
/// </summary>
private long GetCurrentUserId()
{
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return long.TryParse(userIdClaim, out var userId) ? userId : 0;
}
}
/// <summary>
/// 删除会话请求
/// </summary>
public class DeleteSessionRequest
{
/// <summary>
/// 会话ID
/// </summary>
public long SessionId { get; set; }
}