using F9WebAiTest.Application.Common; using F9WebAiTest.Application.Dtos; using F9WebAiTest.Application.Dtos.Notice; using F9WebAiTest.Application.Services; using F9WebAiTest.Application.Services.Auth; using F9WebAiTest.Application.Services.Notice; using F9WebAiTest.Domain.Entities; using F9WebAiTest.Domain.Entities.Notice; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace F9WebAiTest.Api.Controllers.Notice; // ==================== 消息类型管理(管理员) ==================== [ApiController] [Route("api/notification/type")] [Authorize] public class NotificationTypeController : ControllerBase { private readonly INotificationService _svc; public NotificationTypeController(INotificationService svc) => _svc = svc; [HttpGet] public async Task GetList() => Ok(ApiResult>.Ok(await _svc.GetTypeListAsync())); [HttpPost] public async Task Create([FromBody] NotificationTypeCreateDto dto) { try { return Ok(ApiResult.Ok(await _svc.CreateTypeAsync(dto, GetUserId()), "创建成功")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } [HttpPut("{id}")] public async Task Update(long id, [FromBody] NotificationTypeCreateDto dto) { try { return Ok(ApiResult.Ok(await _svc.UpdateTypeAsync(id, dto), "更新成功")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } [HttpDelete("{id}")] public async Task Delete(long id) { try { await _svc.DeleteTypeAsync(id); return Ok(ApiResult.Ok(null, "删除成功")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } private long GetUserId() => long.Parse(User.FindFirst("id")!.Value); } // ==================== 用户端:订阅 + 消息 ==================== [ApiController] [Route("api/notification")] [Authorize] public class NotificationController : ControllerBase { private readonly INotificationService _svc; private readonly IMediator _mediator; private readonly IAuthService _authService; public NotificationController(INotificationService svc, IMediator mediator, IAuthService authService) { _svc = svc; _mediator = mediator; _authService = authService; } // 可订阅的消息类型列表(有权限的才可见/可订阅) [HttpGet("subscribe")] public async Task GetSubscribeList() => Ok(ApiResult>.Ok(await _svc.GetSubscribeListAsync(GetUserId()))); // 订阅 / 取消订阅 [HttpPost("subscribe")] public async Task Subscribe([FromBody] SubscribeDto dto) { try { await _svc.SubscribeAsync(GetUserId(), dto.NotificationTypeId, dto.Subscribe); return Ok(ApiResult.Ok(null, dto.Subscribe ? "订阅成功" : "已取消订阅")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } // 我的消息列表(readStatus: 0未读 1已读;category: 0通知 1待办 2公告) [HttpGet("messages")] public async Task GetMyMessages([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20, [FromQuery] int? readStatus = null, [FromQuery] int? category = null) => Ok(ApiResult>.Ok(await _svc.GetMyMessagesAsync(GetUserId(), pageIndex, pageSize, readStatus, category))); // 我的待办列表 [HttpGet("todos")] public async Task GetMyTodos([FromQuery] int? status = null) => Ok(ApiResult>.Ok(await _svc.GetMyTodosAsync(GetUserId(), status))); // 完成待办 [HttpPost("todos/{id}/complete")] public async Task CompleteTodo(long id, [FromBody] CompleteTodoDto dto) { try { await _svc.CompleteTodoAsync(GetUserId(), id, dto.HandleResult); return Ok(ApiResult.Ok(null, "已完成")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } // 标记已读 [HttpPut("messages/{id}/read")] public async Task MarkRead(long id) { try { await _svc.MarkReadAsync(GetUserId(), id); return Ok(ApiResult.Ok(null)); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } // 全部已读 [HttpPut("messages/read-all")] public async Task MarkAllRead() { await _svc.MarkAllReadAsync(GetUserId()); return Ok(ApiResult.Ok(null)); } // 未读数量 [HttpGet("unread-count")] public async Task GetUnreadCount() => Ok(ApiResult.Ok(new UnreadCountDto { Count = await _svc.GetUnreadCountAsync(GetUserId()) })); // 触发一条消息(模拟业务系统触发,用于演示/测试) [HttpPost("trigger")] public async Task Trigger([FromBody] TriggerDto dto) { try { var msgId = await _mediator.Send(new CreateNotificationCommand { NotificationTypeCode = dto.Code, BusinessType = dto.BusinessType ?? "Manual", BusinessId = dto.BusinessId ?? Guid.NewGuid().ToString("N"), Title = dto.Title ?? "测试消息", Content = dto.Content ?? "这是一条测试消息", Priority = dto.Priority ?? NotificationPriority.Normal, RoutePath = dto.RoutePath ?? "", ForceReceivers = dto.AssigneeIds ?? new List(), AssigneeIds = dto.AssigneeIds ?? new List(), CreatorId = GetUserId(), CreatorName = User.FindFirst("realName")?.Value ?? "系统" }); return Ok(ApiResult.Ok(new { id = msgId }, "消息已创建并即时推送给在线接收人")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } // 发送广播通知(拥有通知广播权限的用户可发送,空接收人 = 订阅广播) [HttpPost("broadcast")] public async Task Broadcast([FromBody] BroadcastNotificationDto dto) { try { var userId = GetUserId(); var perms = await _authService.GetUserPermissionsAsync(userId); if (!perms.Contains("notification:broadcast")) return StatusCode(403, ApiResult.Fail("您没有发送广播通知的权限", 403)); var msgId = await _mediator.Send(new CreateNotificationCommand { NotificationTypeCode = "Broadcast", BusinessType = "Broadcast", BusinessId = Guid.NewGuid().ToString("N"), Title = dto.Title, Content = dto.Content, Priority = dto.Priority ?? NotificationPriority.Normal, RoutePath = dto.RoutePath ?? "", ForceReceivers = new List(), CreatorId = userId, CreatorName = User.FindFirst("realName")?.Value ?? "系统" }); return Ok(ApiResult.Ok(new { id = msgId }, "广播消息已创建")); } catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult.Fail(ex.Message, ex.Code)); } } private long GetUserId() => long.Parse(User.FindFirst("id")!.Value); } public class TriggerDto { public string Code { get; set; } = "TeyeFound"; public string Title { get; set; } public string Content { get; set; } public string BusinessType { get; set; } public string BusinessId { get; set; } public NotificationPriority? Priority { get; set; } public string RoutePath { get; set; } public List AssigneeIds { get; set; } }