using CampusErrand.Data; using CampusErrand.Models; using CampusErrand.Models.Dtos; using CampusErrand.Helpers; using Microsoft.EntityFrameworkCore; namespace CampusErrand.Endpoints; public static class MessageEndpoints { public static void MapMessageEndpoints(this WebApplication app) { // 获取未读消息数 app.MapGet("/api/messages/unread-count", async (HttpContext httpContext, AppDbContext db) => { var userIdClaim = httpContext.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier); if (userIdClaim == null) return Results.Unauthorized(); var userId = int.Parse(userIdClaim.Value); // 获取该用户可见的系统消息(按目标类型过滤) var user = await db.Users.FindAsync(userId); var visibleSystemMessages = await BusinessHelpers.GetVisibleSystemMessages(db, userId, user); var visibleSystemMessageIds = visibleSystemMessages.Select(m => m.Id).ToHashSet(); // 已读的系统消息 ID var readSystemIds = await db.MessageReads .Where(r => r.UserId == userId && r.MessageType == MessageType.System) .Select(r => r.MessageId) .ToListAsync(); var systemUnread = visibleSystemMessageIds.Count(id => !readSystemIds.Contains(id)); // 订单通知:用户相关的订单中状态变更过的订单数 var orderNotifications = await db.Orders .Where(o => (o.OwnerId == userId || o.RunnerId == userId) && o.Status != OrderStatus.Pending) .Select(o => o.Id) .ToListAsync(); var readOrderNotificationIds = await db.MessageReads .Where(r => r.UserId == userId && r.MessageType == MessageType.OrderNotification) .Select(r => r.MessageId) .ToListAsync(); var orderNotificationUnread = orderNotifications.Count(id => !readOrderNotificationIds.Contains(id)); return Results.Ok(new UnreadCountResponse { SystemUnread = systemUnread, OrderNotificationUnread = orderNotificationUnread, TotalUnread = systemUnread + orderNotificationUnread }); }).RequireAuthorization(); // 获取系统消息列表 app.MapGet("/api/messages/system", async (HttpContext httpContext, AppDbContext db) => { var userIdClaim = httpContext.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier); if (userIdClaim == null) return Results.Unauthorized(); var userId = int.Parse(userIdClaim.Value); var user = await db.Users.FindAsync(userId); var messages = await BusinessHelpers.GetVisibleSystemMessages(db, userId, user); // 获取已读记录 var readIds = await db.MessageReads .Where(r => r.UserId == userId && r.MessageType == MessageType.System) .Select(r => r.MessageId) .ToListAsync(); var result = messages .OrderByDescending(m => m.CreatedAt) .Select(m => new SystemMessageResponse { Id = m.Id, Title = m.Title, ContentPreview = m.Content.Length > 100 ? m.Content[..100] + "…" : m.Content, ThumbnailUrl = m.ThumbnailUrl, CreatedAt = m.CreatedAt, IsRead = readIds.Contains(m.Id) }) .ToList(); // 标记所有为已读 foreach (var msg in messages.Where(m => !readIds.Contains(m.Id))) { db.MessageReads.Add(new MessageRead { UserId = userId, MessageType = MessageType.System, MessageId = msg.Id, ReadAt = DateTime.UtcNow }); } await db.SaveChangesAsync(); return Results.Ok(result); }).RequireAuthorization(); // 获取系统消息详情 app.MapGet("/api/messages/system/{id}", async (int id, HttpContext httpContext, AppDbContext db) => { var userIdClaim = httpContext.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier); if (userIdClaim == null) return Results.Unauthorized(); var message = await db.SystemMessages.FindAsync(id); if (message == null) return Results.NotFound(new { code = 404, message = "消息不存在" }); return Results.Ok(new SystemMessageDetailResponse { Id = message.Id, Title = message.Title, Content = message.Content, ThumbnailUrl = message.ThumbnailUrl, CreatedAt = message.CreatedAt }); }).RequireAuthorization(); // 获取订单通知列表 app.MapGet("/api/messages/order-notifications", async (string? category, HttpContext httpContext, AppDbContext db) => { var userIdClaim = httpContext.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier); if (userIdClaim == null) return Results.Unauthorized(); var userId = int.Parse(userIdClaim.Value); // 查询用户相关的订单(状态已变更的) var query = db.Orders .Where(o => (o.OwnerId == userId || o.RunnerId == userId) && o.Status != OrderStatus.Pending); // 按分类筛选 if (!string.IsNullOrEmpty(category)) { query = category.ToLower() switch { "accepted" => query.Where(o => o.Status == OrderStatus.InProgress), "completed" => query.Where(o => o.Status == OrderStatus.Completed), "cancelled" => query.Where(o => o.Status == OrderStatus.Cancelled), _ => query }; } var orders = await query .OrderByDescending(o => o.AcceptedAt ?? o.CreatedAt) .Select(o => new OrderNotificationResponse { Id = o.Id, OrderNo = o.OrderNo, OrderType = o.OrderType.ToString(), Title = o.Status == OrderStatus.InProgress ? (o.OwnerId == userId ? "订单已被接取" : "您已接取订单") : o.Status == OrderStatus.Completed ? (o.RunnerId == userId ? "单主已确认完成" : "订单已完成") : o.Status == OrderStatus.Cancelled ? "订单已取消" : o.Status == OrderStatus.WaitConfirm ? (o.OwnerId == userId ? "跑腿已提交完成,请确认" : "等待单主确认完成") : o.Status == OrderStatus.Appealing ? "订单申诉中" : "订单状态变更", ItemName = o.ItemName, Status = o.Status.ToString(), CreatedAt = o.AcceptedAt ?? o.CreatedAt }) .ToListAsync(); // 标记订单通知为已读 var orderIds = orders.Select(o => o.Id).ToList(); var readIds = await db.MessageReads .Where(r => r.UserId == userId && r.MessageType == MessageType.OrderNotification && orderIds.Contains(r.MessageId)) .Select(r => r.MessageId) .ToListAsync(); foreach (var orderId in orderIds.Where(id => !readIds.Contains(id))) { db.MessageReads.Add(new MessageRead { UserId = userId, MessageType = MessageType.OrderNotification, MessageId = orderId, ReadAt = DateTime.UtcNow }); } await db.SaveChangesAsync(); return Results.Ok(orders); }).RequireAuthorization(); // 管理端获取已发送通知列表 app.MapGet("/api/admin/notifications", async (AppDbContext db) => { var list = await db.SystemMessages .OrderByDescending(m => m.CreatedAt) .Select(m => new { m.Id, m.Title, ContentPreview = m.Content.Length > 80 ? m.Content.Substring(0, 80) + "…" : m.Content, m.ThumbnailUrl, TargetType = m.TargetType.ToString(), m.TargetUserIds, m.CreatedAt }) .ToListAsync(); return Results.Ok(list); }).RequireAuthorization("AdminOnly"); // 管理端发布系统通知 app.MapPost("/api/admin/notifications", async (CreateNotificationRequest request, AppDbContext db) => { // 校验 var errors = new List(); if (string.IsNullOrWhiteSpace(request.Title)) errors.Add(new { field = "title", message = "标题不能为空" }); if (string.IsNullOrWhiteSpace(request.Content)) errors.Add(new { field = "content", message = "正文不能为空" }); if (errors.Count > 0) return Results.BadRequest(new { code = 400, message = "校验失败", errors }); if (!Enum.TryParse(request.TargetType, true, out var targetType) || !Enum.IsDefined(targetType)) return Results.BadRequest(new { code = 400, message = "目标类型不合法" }); var message = new SystemMessage { Title = request.Title, Content = request.Content, ThumbnailUrl = request.ThumbnailUrl, TargetType = targetType, TargetUserIds = request.TargetUserIds != null ? System.Text.Json.JsonSerializer.Serialize(request.TargetUserIds) : null, CreatedAt = DateTime.UtcNow }; db.SystemMessages.Add(message); await db.SaveChangesAsync(); return Results.Created($"/api/admin/notifications/{message.Id}", new SystemMessageDetailResponse { Id = message.Id, Title = message.Title, Content = message.Content, ThumbnailUrl = message.ThumbnailUrl, CreatedAt = message.CreatedAt }); }).RequireAuthorization("AdminOnly"); // 管理端删除通知 app.MapDelete("/api/admin/notifications/{id}", async (int id, AppDbContext db) => { var msg = await db.SystemMessages.FindAsync(id); if (msg == null) return Results.NotFound(new { code = 404, message = "通知不存在" }); // 删除关联的已读记录 db.MessageReads.RemoveRange( db.MessageReads.Where(r => r.MessageType == MessageType.System && r.MessageId == id)); db.SystemMessages.Remove(msg); await db.SaveChangesAsync(); return Results.Ok(new { message = "已删除" }); }).RequireAuthorization("AdminOnly"); } }