Asoka.Wang 2b3f9acdce 123
2025-09-22 19:09:47 +08:00

552 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>
/// 通知服务 系统消息
/// </summary>
[DynamicApi(Area = "app")]
public class SystemMessageService : BaseService, ISystemMessageService, IDynamicApi
{
private readonly INotificationTemplateService _templateService;
private readonly IRepositoryBase<NotificationHistoryEntity> _notificationHistoryRepository;
public SystemMessageService(
INotificationTemplateService templateService,
IRepositoryBase<NotificationHistoryEntity> notificationHistoryRepository)
{
_templateService = templateService;
_notificationHistoryRepository = notificationHistoryRepository;
}
#region
/// <summary>
/// 发送系统消息
/// 业务场景:工作任务分配、设备状态变更、排班通知等
/// </summary>
[HttpPost]
public async Task<SendSystemMessageOutput> 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}");
}
}
/// <summary>
/// 发送带操作按钮的系统消息
/// 业务场景:任务确认、审批流程、操作确认等交互式场景
/// </summary>
[HttpPost]
public async Task<SendSystemMessageOutput> 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
/// <summary>
/// 批量发送系统消息
/// 业务场景:排班变更通知、紧急通知、系统维护通知等需要群发的场景
/// </summary>
[HttpPost]
public async Task<BatchSendSystemMessageOutput> BatchSendSystemMessageAsync(BatchSendSystemMessageInput input)
{
var results = new Dictionary<long, SendSystemMessageOutput>();
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<NotificationHistoryEntity>();
// 注释系统消息类型统一使用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);
}
/// <summary>
/// 个性化批量发送系统消息
/// 业务场景:个性化任务分配通知、个性化提醒等需要不同内容的场景
/// </summary>
[HttpPost]
public async Task<BatchSendSystemMessageOutput> BatchSendPersonalizedSystemMessageAsync(List<SystemMessageItem> messageItems)
{
var results = new Dictionary<long, SendSystemMessageOutput>();
if (messageItems == null || !messageItems.Any())
{
Logger.LogWarning("个性化批量发送系统消息:消息项列表为空");
return BatchSendSystemMessageOutput.Create(results);
}
try
{
var notificationHistories = new List<NotificationHistoryEntity>();
var currentTime = DateTime.Now;
var successfulItems = new List<SystemMessageItem>();
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
/// <summary>
/// 使用模板发送系统消息
/// 业务场景:标准化通知,如任务分配模板、维护提醒模板等
/// </summary>
[HttpPost]
public async Task<SendSystemMessageOutput> 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
/// <summary>
/// 标记消息为已读
/// 业务场景:用户查看消息后更新状态,用于消息中心的已读/未读状态管理
/// </summary>
[HttpPost]
public async Task<SystemMessageStatusOutput> 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}");
}
}
/// <summary>
/// 批量标记消息为已读
/// 业务场景:用户批量处理消息,提高操作效率
/// </summary>
[HttpPost]
public async Task<SystemMessageStatusOutput> BatchMarkMessagesAsReadAsync(List<long> 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}");
}
}
/// <summary>
/// 删除消息
/// 业务场景:用户清理不需要的消息,实现软删除以保留审计记录
/// </summary>
[HttpPost]
public async Task<SystemMessageStatusOutput> 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}");
}
}
/// <summary>
/// 获取用户未读消息数量
/// 业务场景:消息中心红点提示、导航栏未读消息数显示
/// </summary>
public async Task<int> 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
}