using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ZhonTai.Admin.Services;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;
using NPP.SmartSchedue.Api.Contracts.Services.Notification;
using NPP.SmartSchedue.Api.Contracts.Services.Notification.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Notification.Output;
using ZhonTai.Admin.Core.Repositories;
using NPP.SmartSchedue.Api.Contracts.Domain.Notification;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
namespace NPP.SmartSchedue.Api.Services.Notification;
///
/// 通知服务 系统消息
///
[DynamicApi(Area = "app")]
public class SystemMessageService : BaseService, ISystemMessageService, IDynamicApi
{
private readonly INotificationTemplateService _templateService;
private readonly IRepositoryBase _notificationHistoryRepository;
public SystemMessageService(
INotificationTemplateService templateService,
IRepositoryBase notificationHistoryRepository)
{
_templateService = templateService;
_notificationHistoryRepository = notificationHistoryRepository;
}
#region 单个消息发送
///
/// 发送系统消息
/// 业务场景:工作任务分配、设备状态变更、排班通知等
///
[HttpPost]
public async Task SendSystemMessageAsync(SendSystemMessageInput input)
{
try
{
if (input.RecipientPersonnelId <= 0)
{
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, "收件人ID无效");
}
if (string.IsNullOrWhiteSpace(input.Title) || string.IsNullOrWhiteSpace(input.Content))
{
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, "消息标题或内容不能为空");
}
var currentTime = DateTime.Now;
// 创建通知历史记录
var notificationHistory = new NotificationHistoryEntity
{
NotificationSettingId = input.NotificationSettingId, // 临时设置,实际应该从配置获取
NotificationType = (int)NotificationTypeEnum.SystemMessage,
RecipientPersonnelId = input.RecipientPersonnelId,
NotificationTitle = input.Title,
NotificationContent = input.Content,
BusinessType = input.BusinessType,
BusinessId = input.BusinessId,
SendStatus = (int)NotificationStatusEnum.Success,
ActualSendTime = currentTime,
PlannedSendTime = currentTime,
CreatedTime = currentTime
};
var result = await _notificationHistoryRepository.InsertAsync(notificationHistory);
return SendSystemMessageOutput.CreateSuccess((long)result.Id, input.RecipientPersonnelId, currentTime);
}
catch (Exception ex)
{
Logger.LogError(ex, "发送系统消息失败:收件人 {RecipientId},标题:{Title}", input.RecipientPersonnelId, input.Title);
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, $"发送失败:{ex.Message}");
}
}
///
/// 发送带操作按钮的系统消息
/// 业务场景:任务确认、审批流程、操作确认等交互式场景
///
[HttpPost]
public async Task SendSystemMessageWithActionsAsync(SendSystemMessageWithActionsInput input)
{
try
{
if (input.RecipientPersonnelId <= 0)
{
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, "收件人ID无效");
}
if (string.IsNullOrWhiteSpace(input.Title) || string.IsNullOrWhiteSpace(input.Content))
{
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, "消息标题或内容不能为空");
}
var currentTime = DateTime.Now;
// 序列化操作按钮
var actionsJson = input.Actions != null && input.Actions.Any()
? System.Text.Json.JsonSerializer.Serialize(input.Actions)
: "";
// 创建通知历史记录
var notificationHistory = new NotificationHistoryEntity
{
NotificationSettingId = 1, // 临时设置,实际应该从配置获取
NotificationType = (int)NotificationTypeEnum.SystemMessage,
RecipientPersonnelId = input.RecipientPersonnelId,
NotificationTitle = input.Title,
NotificationContent = input.Content,
BusinessType = input.BusinessType,
BusinessId = input.BusinessId,
SendStatus = (int)NotificationStatusEnum.Success,
ActualSendTime = currentTime,
PlannedSendTime = currentTime,
BusinessData = actionsJson, // 存储操作按钮数据
CreatedTime = currentTime
};
var result = await _notificationHistoryRepository.InsertAsync(notificationHistory);
return SendSystemMessageOutput.CreateSuccess((long)result.Id, input.RecipientPersonnelId, currentTime);
}
catch (Exception ex)
{
Logger.LogError(ex, "发送带操作按钮的系统消息失败:收件人 {RecipientId},标题:{Title}", input.RecipientPersonnelId, input.Title);
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, $"发送失败:{ex.Message}");
}
}
#endregion
#region 批量消息发送
///
/// 批量发送系统消息
/// 业务场景:排班变更通知、紧急通知、系统维护通知等需要群发的场景
///
[HttpPost]
public async Task BatchSendSystemMessageAsync(BatchSendSystemMessageInput input)
{
var results = new Dictionary();
if (input.RecipientPersonnelIds == null || !input.RecipientPersonnelIds.Any())
{
Logger.LogWarning("批量发送系统消息:收件人列表为空");
return BatchSendSystemMessageOutput.Create(results);
}
if (string.IsNullOrWhiteSpace(input.Title) || string.IsNullOrWhiteSpace(input.Content))
{
foreach (var recipientId in input.RecipientPersonnelIds)
{
results[recipientId] = SendSystemMessageOutput.CreateFailure(recipientId, "消息标题或内容不能为空");
}
return BatchSendSystemMessageOutput.Create(results);
}
// 去重收件人
var uniqueRecipients = input.RecipientPersonnelIds.Distinct().Where(id => id > 0).ToList();
try
{
var notificationHistories = new List();
// 注释:系统消息类型统一使用NotificationTypeEnum.SystemMessage
var currentTime = DateTime.Now;
// 批量创建通知记录
foreach (var recipientId in uniqueRecipients)
{
var notificationHistory = new NotificationHistoryEntity
{
NotificationSettingId = 1, // 临时设置,实际应该从配置获取
NotificationType = (int)NotificationTypeEnum.SystemMessage,
RecipientPersonnelId = recipientId,
NotificationTitle = input.Title,
NotificationContent = input.Content,
BusinessType = input.BusinessType,
BusinessId = input.BusinessId,
SendStatus = (int)NotificationStatusEnum.Success,
ActualSendTime = currentTime,
PlannedSendTime = currentTime,
CreatedTime = currentTime
};
notificationHistories.Add(notificationHistory);
}
// 批量插入
var insertedEntities = await _notificationHistoryRepository.InsertAsync(notificationHistories);
// 创建成功结果
for (int i = 0; i < uniqueRecipients.Count; i++)
{
var recipientId = uniqueRecipients[i];
var entity = insertedEntities[i];
results[recipientId] = SendSystemMessageOutput.CreateSuccess((long)entity.Id, recipientId, currentTime);
}
Logger.LogInformation("批量发送系统消息完成:总数 {Total},成功 {Success}",
input.RecipientPersonnelIds.Count, results.Values.Count(r => r.Success));
}
catch (Exception ex)
{
Logger.LogError(ex, "批量发送系统消息失败");
// 如果批量操作失败,将所有结果设为失败
foreach (var recipientId in uniqueRecipients)
{
results[recipientId] = SendSystemMessageOutput.CreateFailure(recipientId, $"批量发送失败:{ex.Message}");
}
}
return BatchSendSystemMessageOutput.Create(results);
}
///
/// 个性化批量发送系统消息
/// 业务场景:个性化任务分配通知、个性化提醒等需要不同内容的场景
///
[HttpPost]
public async Task BatchSendPersonalizedSystemMessageAsync(List messageItems)
{
var results = new Dictionary();
if (messageItems == null || !messageItems.Any())
{
Logger.LogWarning("个性化批量发送系统消息:消息项列表为空");
return BatchSendSystemMessageOutput.Create(results);
}
try
{
var notificationHistories = new List();
var currentTime = DateTime.Now;
var successfulItems = new List();
foreach (var item in messageItems)
{
try
{
if (item.RecipientPersonnelId <= 0 ||
string.IsNullOrWhiteSpace(item.Title) ||
string.IsNullOrWhiteSpace(item.Content))
{
results[item.RecipientPersonnelId] = SendSystemMessageOutput.CreateFailure(
item.RecipientPersonnelId, "消息项无效:收件人ID、标题或内容为空");
continue;
}
// 渲染模板变量(如果有)
var title = item.Title;
var content = item.Content;
if (item.Variables != null && item.Variables.Any())
{
var titleResult = await _templateService.RenderTemplateAsync(new RenderTemplateInput
{
Template = item.Title,
Variables = item.Variables
});
var contentResult = await _templateService.RenderTemplateAsync(new RenderTemplateInput
{
Template = item.Content,
Variables = item.Variables
});
title = titleResult.RenderedContent;
content = contentResult.RenderedContent;
}
// 序列化操作按钮
var actionsJson = item.Actions != null && item.Actions.Any()
? System.Text.Json.JsonSerializer.Serialize(item.Actions)
: "";
var notificationHistory = new NotificationHistoryEntity
{
NotificationSettingId = 1, // 临时设置,实际应该从配置获取
NotificationType = (int)NotificationTypeEnum.SystemMessage,
RecipientPersonnelId = item.RecipientPersonnelId,
NotificationTitle = title,
NotificationContent = content,
BusinessType = item.BusinessType,
BusinessId = item.BusinessId,
SendStatus = (int)NotificationStatusEnum.Success,
ActualSendTime = currentTime,
PlannedSendTime = currentTime,
BusinessData = actionsJson,
CreatedTime = currentTime
};
notificationHistories.Add(notificationHistory);
successfulItems.Add(item);
}
catch (Exception ex)
{
Logger.LogError(ex, "处理个性化消息项失败:收件人 {RecipientId}", item.RecipientPersonnelId);
results[item.RecipientPersonnelId] = SendSystemMessageOutput.CreateFailure(
item.RecipientPersonnelId, $"处理失败:{ex.Message}");
}
}
// 批量插入成功的记录
if (notificationHistories.Any())
{
var insertedEntities = await _notificationHistoryRepository.InsertAsync(notificationHistories);
// 创建成功结果
for (int i = 0; i < successfulItems.Count; i++)
{
var item = successfulItems[i];
var entity = insertedEntities[i];
results[item.RecipientPersonnelId] = SendSystemMessageOutput.CreateSuccess(
(long)entity.Id, item.RecipientPersonnelId, currentTime);
}
}
Logger.LogInformation("个性化批量发送系统消息完成:总数 {Total},成功 {Success},失败 {Failed}",
messageItems.Count, results.Values.Count(r => r.Success), results.Values.Count(r => !r.Success));
}
catch (Exception ex)
{
Logger.LogError(ex, "个性化批量发送系统消息失败");
// 如果批量操作失败,将所有结果设为失败
foreach (var item in messageItems)
{
if (!results.ContainsKey(item.RecipientPersonnelId))
{
results[item.RecipientPersonnelId] = SendSystemMessageOutput.CreateFailure(
item.RecipientPersonnelId, $"批量操作失败:{ex.Message}");
}
}
}
return BatchSendSystemMessageOutput.Create(results);
}
#endregion
#region 消息模板
///
/// 使用模板发送系统消息
/// 业务场景:标准化通知,如任务分配模板、维护提醒模板等
///
[HttpPost]
public async Task SendSystemMessageByTemplateAsync(SendSystemMessageByTemplateInput input)
{
try
{
// 渲染模板
var titleResult = await _templateService.RenderTemplateAsync(new RenderTemplateInput
{
Template = input.TitleTemplate,
Variables = input.Variables
});
var contentResult = await _templateService.RenderTemplateAsync(new RenderTemplateInput
{
Template = input.ContentTemplate,
Variables = input.Variables
});
var title = titleResult.RenderedContent;
var content = contentResult.RenderedContent;
// 创建发送消息的输入模型
var sendInput = new SendSystemMessageInput
{
RecipientPersonnelId = input.RecipientPersonnelId,
Title = title,
Content = content,
MessageType = input.MessageType,
BusinessType = input.BusinessType,
BusinessId = input.BusinessId
};
// 发送消息
return await SendSystemMessageAsync(sendInput);
}
catch (Exception ex)
{
Logger.LogError(ex, "使用模板发送系统消息失败:收件人 {RecipientId}", input.RecipientPersonnelId);
return SendSystemMessageOutput.CreateFailure(input.RecipientPersonnelId, $"模板发送失败:{ex.Message}");
}
}
#endregion
#region 消息管理
///
/// 标记消息为已读
/// 业务场景:用户查看消息后更新状态,用于消息中心的已读/未读状态管理
///
[HttpPost]
public async Task MarkMessageAsReadAsync(long messageId, long recipientPersonnelId)
{
try
{
var message = await _notificationHistoryRepository
.Where(x => x.Id == messageId &&
x.RecipientPersonnelId == recipientPersonnelId &&
!x.IsDeleted)
.FirstAsync();
if (message == null)
{
Logger.LogWarning("消息不存在或已被删除:消息ID {MessageId},收件人 {RecipientId}", messageId, recipientPersonnelId);
return SystemMessageStatusOutput.CreateFailure(recipientPersonnelId, "消息不存在或已被删除");
}
// 系统消息的已读状态通过SendStatus管理,这里暂时不做处理
// 实际项目中可能需要扩展实体或使用其他方式管理已读状态
// 这里更新ModifiedTime表示已读
message.ModifiedTime = DateTime.Now;
await _notificationHistoryRepository.UpdateAsync(message);
Logger.LogDebug("消息标记为已读:消息ID {MessageId},收件人 {RecipientId}", messageId, recipientPersonnelId);
return SystemMessageStatusOutput.CreateSuccess(recipientPersonnelId, 1, "消息已标记为已读");
}
catch (Exception ex)
{
Logger.LogError(ex, "标记消息为已读失败:消息ID {MessageId},收件人 {RecipientId}", messageId, recipientPersonnelId);
return SystemMessageStatusOutput.CreateFailure(recipientPersonnelId, $"标记为已读失败:{ex.Message}");
}
}
///
/// 批量标记消息为已读
/// 业务场景:用户批量处理消息,提高操作效率
///
[HttpPost]
public async Task BatchMarkMessagesAsReadAsync(List messageIds, long recipientPersonnelId)
{
if (messageIds == null || !messageIds.Any())
{
Logger.LogWarning("批量标记消息为已读:消息ID列表为空");
return SystemMessageStatusOutput.CreateFailure(recipientPersonnelId, "消息ID列表为空");
}
try
{
var currentTime = DateTime.Now;
// 查询消息
var messages = await _notificationHistoryRepository
.Where(x => messageIds.Contains(x.Id) &&
x.RecipientPersonnelId == recipientPersonnelId &&
!x.IsDeleted)
.ToListAsync();
if (!messages.Any())
{
Logger.LogInformation("没有找到需要标记为已读的消息:收件人 {RecipientId}", recipientPersonnelId);
return SystemMessageStatusOutput.CreateSuccess(recipientPersonnelId, 0, "没有找到需要标记为已读的消息");
}
// 批量更新
foreach (var message in messages)
{
message.ModifiedTime = currentTime;
}
await _notificationHistoryRepository.UpdateAsync(messages);
Logger.LogInformation("批量标记消息为已读完成:收件人 {RecipientId},更新数量 {Count}", recipientPersonnelId, messages.Count);
return SystemMessageStatusOutput.CreateSuccess(recipientPersonnelId, messages.Count, $"成功标记{messages.Count}条消息为已读");
}
catch (Exception ex)
{
Logger.LogError(ex, "批量标记消息为已读失败:收件人 {RecipientId}", recipientPersonnelId);
return SystemMessageStatusOutput.CreateFailure(recipientPersonnelId, $"批量标记为已读失败:{ex.Message}");
}
}
///
/// 删除消息
/// 业务场景:用户清理不需要的消息,实现软删除以保留审计记录
///
[HttpPost]
public async Task DeleteMessageAsync(long messageId, long recipientPersonnelId)
{
try
{
var message = await _notificationHistoryRepository
.Where(x => x.Id == messageId &&
x.RecipientPersonnelId == recipientPersonnelId &&
!x.IsDeleted)
.FirstAsync();
if (message == null)
{
Logger.LogWarning("消息不存在或已被删除:消息ID {MessageId},收件人 {RecipientId}", messageId, recipientPersonnelId);
return SystemMessageStatusOutput.CreateFailure(recipientPersonnelId, "消息不存在或已被删除");
}
// 软删除
message.IsDeleted = true;
message.ModifiedTime = DateTime.Now;
await _notificationHistoryRepository.UpdateAsync(message);
Logger.LogInformation("消息删除成功:消息ID {MessageId},收件人 {RecipientId}", messageId, recipientPersonnelId);
return SystemMessageStatusOutput.CreateSuccess(recipientPersonnelId, 1, "消息删除成功");
}
catch (Exception ex)
{
Logger.LogError(ex, "删除消息失败:消息ID {MessageId},收件人 {RecipientId}", messageId, recipientPersonnelId);
return SystemMessageStatusOutput.CreateFailure(recipientPersonnelId, $"删除消息失败:{ex.Message}");
}
}
///
/// 获取用户未读消息数量
/// 业务场景:消息中心红点提示、导航栏未读消息数显示
///
public async Task GetUnreadMessageCountAsync(long recipientPersonnelId)
{
try
{
var count = await _notificationHistoryRepository
.Where(x => x.RecipientPersonnelId == recipientPersonnelId &&
x.NotificationType == (int)NotificationTypeEnum.SystemMessage &&
!x.IsDeleted)
.CountAsync();
return (int)count;
}
catch (Exception ex)
{
Logger.LogError(ex, "获取用户未读消息数量失败:收件人 {RecipientId}", recipientPersonnelId);
return 0;
}
}
#endregion
#region 私有辅助方法
// 注:原有的消息类型转换方法已移除,因为实体结构调整后不再需要
#endregion
}