campus-errand/server/Endpoints/MessageEndpoints.cs
18631081161 681d2b5fe8
All checks were successful
continuous-integration/drone/push Build is passing
提现
2026-04-02 16:55:18 +08:00

262 lines
11 KiB
C#

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<object>();
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<MessageTargetType>(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");
}
}