FlowNotifyService.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. using Admin.NET.Core.Service;
  2. using Microsoft.AspNetCore.SignalR;
  3. namespace Admin.NET.Plugin.ApprovalFlow.Service;
  4. /// <summary>
  5. /// 流程通知服务 — 按 JSON 配置分渠道调度
  6. /// </summary>
  7. public class FlowNotifyService : ITransient
  8. {
  9. private readonly IHubContext<OnlineUserHub, IOnlineUserHub> _hubContext;
  10. private readonly SysCacheService _cacheService;
  11. public FlowNotifyService(
  12. IHubContext<OnlineUserHub, IOnlineUserHub> hubContext,
  13. SysCacheService cacheService)
  14. {
  15. _hubContext = hubContext;
  16. _cacheService = cacheService;
  17. }
  18. public async Task NotifyUsers(List<long> userIds, FlowNotification notification)
  19. {
  20. if (userIds.Count == 0) return;
  21. var cfg = App.GetConfig<NotifyChannelConfig>("ApprovalFlow:Notify");
  22. if (cfg?.SignalR != false)
  23. await SendSignalR(userIds, notification);
  24. if (cfg?.DingTalk == true)
  25. await SendDingTalk(userIds, notification);
  26. if (cfg?.WorkWeixin == true)
  27. await SendWorkWeixin(userIds, notification);
  28. if (cfg?.Email == true)
  29. await SendEmail(userIds, notification);
  30. if (cfg?.Sms == true)
  31. await SendSms(userIds, notification);
  32. }
  33. public async Task NotifyUrge(List<long> userIds, long instanceId, string title)
  34. {
  35. await NotifyUsers(userIds, new FlowNotification
  36. {
  37. Type = FlowNotificationTypeEnum.Urge,
  38. InstanceId = instanceId,
  39. Title = $"【催办】{title}",
  40. Content = "流程发起人催促您尽快审批,请及时处理。",
  41. });
  42. }
  43. public async Task NotifyNewTask(List<long> userIds, long instanceId, string title, string? nodeName)
  44. {
  45. await NotifyUsers(userIds, new FlowNotification
  46. {
  47. Type = FlowNotificationTypeEnum.NewTask,
  48. InstanceId = instanceId,
  49. Title = $"【待审批】{title}",
  50. Content = $"您有一条新的审批任务({nodeName}),请及时处理。",
  51. });
  52. }
  53. public async Task NotifyFlowCompleted(long initiatorId, long instanceId, string title, FlowInstanceStatusEnum finalStatus)
  54. {
  55. var statusText = finalStatus == FlowInstanceStatusEnum.Approved ? "已通过" : "已拒绝";
  56. await NotifyUsers(new List<long> { initiatorId }, new FlowNotification
  57. {
  58. Type = FlowNotificationTypeEnum.FlowCompleted,
  59. InstanceId = instanceId,
  60. Title = $"【审批{statusText}】{title}",
  61. Content = $"您发起的审批流程已{statusText}。",
  62. });
  63. }
  64. /// <summary>
  65. /// 转办通知 — 通知被转办人
  66. /// </summary>
  67. public async Task NotifyTransferred(long targetUserId, long instanceId, string title, string? fromName)
  68. {
  69. await NotifyUsers(new List<long> { targetUserId }, new FlowNotification
  70. {
  71. Type = FlowNotificationTypeEnum.Transferred,
  72. InstanceId = instanceId,
  73. Title = $"【转办】{title}",
  74. Content = $"{fromName} 将一条审批任务转交给您,请及时处理。",
  75. });
  76. }
  77. /// <summary>
  78. /// 退回通知 — 通知被退回节点的审批人
  79. /// </summary>
  80. public async Task NotifyReturned(List<long> userIds, long instanceId, string title, string? returnedBy)
  81. {
  82. await NotifyUsers(userIds, new FlowNotification
  83. {
  84. Type = FlowNotificationTypeEnum.Returned,
  85. InstanceId = instanceId,
  86. Title = $"【退回】{title}",
  87. Content = $"{returnedBy} 已退回该审批,请重新审核。",
  88. });
  89. }
  90. /// <summary>
  91. /// 加签通知 — 通知被加签人
  92. /// </summary>
  93. public async Task NotifyAddSign(long targetUserId, long instanceId, string title, string? fromName)
  94. {
  95. await NotifyUsers(new List<long> { targetUserId }, new FlowNotification
  96. {
  97. Type = FlowNotificationTypeEnum.AddSign,
  98. InstanceId = instanceId,
  99. Title = $"【加签】{title}",
  100. Content = $"{fromName} 邀请您参与审批,请及时处理。",
  101. });
  102. }
  103. /// <summary>
  104. /// 撤回通知 — 通知被取消的审批人
  105. /// </summary>
  106. public async Task NotifyWithdrawn(List<long> userIds, long instanceId, string title, string? initiatorName)
  107. {
  108. await NotifyUsers(userIds, new FlowNotification
  109. {
  110. Type = FlowNotificationTypeEnum.Withdrawn,
  111. InstanceId = instanceId,
  112. Title = $"【已撤回】{title}",
  113. Content = $"{initiatorName} 已撤回该审批流程。",
  114. });
  115. }
  116. // ═══════════════════════════════════════════
  117. // 各渠道发送实现
  118. // ═══════════════════════════════════════════
  119. private async Task SendSignalR(List<long> userIds, FlowNotification notification)
  120. {
  121. var onlineUsers = _cacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
  122. var connectionIds = onlineUsers
  123. .Where(u => userIds.Contains(u.Value.UserId))
  124. .Select(u => u.Value.ConnectionId)
  125. .ToList();
  126. if (connectionIds.Count == 0) return;
  127. await _hubContext.Clients.Clients(connectionIds).ReceiveMessage(new
  128. {
  129. title = notification.Title,
  130. message = notification.Content,
  131. type = notification.Type.ToString(),
  132. instanceId = notification.InstanceId,
  133. });
  134. }
  135. private Task SendDingTalk(List<long> userIds, FlowNotification notification)
  136. {
  137. // TODO: 接入 DingTalk 开放平台 API
  138. return Task.CompletedTask;
  139. }
  140. private Task SendWorkWeixin(List<long> userIds, FlowNotification notification)
  141. {
  142. // TODO: 接入企业微信消息推送 API
  143. return Task.CompletedTask;
  144. }
  145. private Task SendEmail(List<long> userIds, FlowNotification notification)
  146. {
  147. // TODO: 接入 SMTP / 邮件服务
  148. return Task.CompletedTask;
  149. }
  150. private Task SendSms(List<long> userIds, FlowNotification notification)
  151. {
  152. // TODO: 接入短信服务
  153. return Task.CompletedTask;
  154. }
  155. }
  156. public class FlowNotification
  157. {
  158. public FlowNotificationTypeEnum Type { get; set; }
  159. public long InstanceId { get; set; }
  160. public string Title { get; set; } = "";
  161. public string Content { get; set; } = "";
  162. }
  163. /// <summary>
  164. /// 通知类型
  165. /// </summary>
  166. public enum FlowNotificationTypeEnum
  167. {
  168. NewTask,
  169. Urge,
  170. FlowCompleted,
  171. Transferred,
  172. Returned,
  173. AddSign,
  174. Withdrawn,
  175. }
  176. /// <summary>
  177. /// 通知渠道配置(来自 ApprovalFlow:Notify JSON)
  178. /// </summary>
  179. public class NotifyChannelConfig
  180. {
  181. public bool SignalR { get; set; } = true;
  182. public bool DingTalk { get; set; }
  183. public bool WorkWeixin { get; set; }
  184. public bool Email { get; set; }
  185. public bool Sms { get; set; }
  186. }