375 lines
13 KiB
C#
375 lines
13 KiB
C#
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; }
|
||
}
|