/// <summary>
        /// 请假工作交接通知
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="order">申请单</param>
        public void AddNotification(MissionskyOAEntities dbContext, OrderModel order)
        {
            if (order == null || order.OrderType == OrderType.Overtime)
            {
                return;
            }

            //申请人
            var applicant = dbContext.Users.FirstOrDefault(it => it.Id == order.ApplyUserId);

            if (applicant == null)
            {
                Log.Error(string.Format("找不到代申请人, Id: {0}", order.ApplyUserId));
                throw new KeyNotFoundException("找不到代申请人。");
            }

            if (order.OrderDets == null || order.OrderDets.Count < 1)
            {
                Log.Error("无效的流程申请单。");
                throw new InvalidOperationException("无效的流程申请单。");
            }

            var detail = order.OrderDets.FirstOrDefault();

            if (detail == null)
            {
                Log.Error("无效的流程申请单详细。");
                throw new InvalidOperationException("无效的流程申请单详细。");
            }

            //消息接收人
            var receiver = dbContext.Users.FirstOrDefault(it => it.Id == detail.Recipient);

            if (receiver == null)
            {
                return;
            }

            #region 3. 批量申请,向代申请推送消息

            var model = new NotificationModel()
            {
                Target        = receiver.Email,
                CreatedUserId = applicant.Id,
                //MessageType = NotificationType.PushMessage,
                MessageType   = NotificationType.Email,
                BusinessType  = BusinessType.Approving,
                Title         = "Missionsky OA Notification",
                MessagePrams  = "请假工作交接通知",
                Scope         = NotificationScope.User,
                CreatedTime   = DateTime.Now,
                TargetUserIds = new List <int> {
                    receiver.Id
                },
                MessageContent = string.Format("{0}请假,时间从{1} {2}到{3} {4}, 总时长为{5}, 并把工作交接给你了, 谢谢。",
                                               applicant.EnglishName,
                                               detail.StartDate.ToString("yyyy-MM-dd"),
                                               OrderExtentions.FormatTimeSpan(detail.StartTime),
                                               detail.EndDate.ToString("yyyy-MM-dd"),
                                               OrderExtentions.FormatTimeSpan(detail.EndTime),
                                               Math.Abs((sbyte)detail.IOHours)
                                               )
            };

            this._notificationService.Add(model, Global.IsProduction); //消息推送

            #endregion
        }
        /// <summary>
        /// 工作流处理消息推送
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="order">申请单</param>
        /// <param name="operaterId">消息推送人Id</param>
        /// <param name="process">流程处理</param>
        /// <param name="receiverId">消息接收人Id</param>
        /// <remarks>receiverId = 0: 表示默认发送到代申请人</remarks>
        public void AddNotification(MissionskyOAEntities dbContext, OrderModel order, int operaterId,
                                    WorkflowProcessModel process, int receiverId = 0)
        {
            #region 1. 获取用户信息

            //代理申请人
            var agentUser = dbContext.Users.FirstOrDefault(it => it.Id == order.ApplyUserId);
            if (agentUser == null)
            {
                Log.Error(string.Format("找不到代申请人, Id: {0}", order.ApplyUserId));
                throw new KeyNotFoundException("找不到代申请人。");
            }

            //消息接收人
            var receiver = dbContext.Users.FirstOrDefault(it => it.Id == receiverId);
            receiver = receiver ?? agentUser;

            //消息推送人
            var operater = (operaterId == receiverId
                ? receiver
                : dbContext.Users.FirstOrDefault(it => it.Id == operaterId));

            if (operater == null)
            {
                Log.Error(string.Format("找不到流程操作人, Id: {0}", receiverId));
                throw new KeyNotFoundException("找不到流程操作人。");
            }
            #endregion

            #region 2. 验证申请单

            if (order == null || order.OrderDets == null || order.OrderDets.Count < 1)
            {
                Log.Error("无效的流程申请单。");
                throw new InvalidOperationException("无效的流程申请单。");
            }

            var detail = order.OrderDets.FirstOrDefault();
            if (detail == null || !detail.IOHours.HasValue)
            {
                Log.Error("无效的流程申请单详细。");
                throw new InvalidOperationException("无效的流程申请单详细。");
            }

            // 委托人
            var recipient = dbContext.Users.FirstOrDefault(it => it.Id == detail.Recipient);

            var checkType = order.OrderType;
            if (checkType == OrderType.DaysOff)
            {
                checkType = OrderType.Overtime;
            }

            #endregion

            #region 3. 批量申请,向代申请推送消息

            var model = new NotificationModel()
            {
                Target        = receiver.Email,
                CreatedUserId = operater.Id,
                //MessageType = NotificationType.PushMessage,
                MessageType   = NotificationType.Email,
                BusinessType  = BusinessType.Approving,
                Title         = "Missionsky OA Notification",
                MessagePrams  = "申请单流程处理",
                Scope         = NotificationScope.User,
                CreatedTime   = DateTime.Now,
                TargetUserIds = new List <int> {
                    receiver.Id
                }
            };

            //流程拒绝时,推送拒绝消息
            if (process.Operation == WorkflowOperation.Rejecte)
            {
                model.MessageContent = string.Format("您的{0}单被拒绝。", order.IsOvertime() ? "加班" : "请假");
            }
            //审批流程结束,或者到财务审批时(需要更新用户假期信息)
            else if (process.Operation == WorkflowOperation.Approve &&
                     (process.NextStep == null || process.NextStep.IsFinanceReviewing()))
            {
                if (receiverId == 0) //默认发送到代申请人
                {
                    model.MessageContent = string.Format("您的{0}单已批准。", order.IsOvertime() ? "加班" : "请假");
                }
                else if (receiver.Id == receiverId) //发送到请假或加班实际申请人
                {
                    //假期汇总信息
                    var summary =
                        dbContext.AttendanceSummaries.FirstOrDefault(
                            it =>
                            it.UserId == receiverId && it.Type == (int)checkType && it.Year == DateTime.Now.Year);

                    if (summary == null)
                    {
                        Log.Error("未找用户假期或加班信息。");
                        throw new KeyNotFoundException("未找用户假期或加班信息。");
                    }

                    //计算剩余天数
                    var days       = Math.Round(detail.IOHours.Value / 8, 1); //申请天数
                    var remainDays = summary.RemainValue.HasValue
                        ? Math.Round(summary.RemainValue.Value / 8, 1) + days
                        : 0.0;                                    //剩余天数

                    days = Math.Abs(days);                        //取绝对值

                    if (order.OrderType == OrderType.AnnualLeave) //年假
                    {
                        model.MessageContent = order.RefOrderId.HasValue
                            ? string.Format("{0}, 您的年假增加{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays)
                            : string.Format("{0}, 您的年假被扣除{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays);
                    }
                    else if (order.OrderType == OrderType.DaysOff) //调休
                    {
                        model.MessageContent = order.RefOrderId.HasValue
                            ? string.Format("{0}, 您的调休假增加{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays)
                            : string.Format("{0}, 您的调休假被扣除{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays);
                    }
                    else if (order.OrderType == OrderType.Overtime) //加班
                    {
                        model.MessageContent = order.RefOrderId.HasValue
                            ? string.Format("{0}, 您的调休假被扣除{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays)
                            : string.Format("{0}, 您的调休假增加{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays);
                    }
                    else //其它假期
                    {
                        model.MessageContent = string.Format("您的{0}单已批准。", order.IsOvertime() ? "加班" : "请假");
                    }
                }
                else
                {
                    Log.Error("推送消息接收人不匹配。");
                    throw new KeyNotFoundException("推送消息接收人不匹配。");
                }
            }
            //申请或审批时,发送到下一步审批人
            else
            {
                if (receiverId == 0) //默认发送到代申请人
                {
                    model.MessageContent = string.Format("请您及时审批{0}的{1}单, 时间从{2} {3}到{4} {5}, 总时长为{6}, {7}。",
                                                         agentUser.EnglishName,
                                                         order.IsOvertime() ? "加班" : "请假",
                                                         detail.StartDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.StartTime),
                                                         detail.EndDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.EndTime),
                                                         Math.Abs((sbyte)detail.IOHours),
                                                         recipient == null ? "没有工作交接人。" : "把工作交接给了" + recipient.EnglishName
                                                         );

                    model.MessageContent = string.Format("您的{0}单已批准。", order.IsOvertime() ? "加班" : "请假");
                }
                else if (receiver.Id == receiverId) //发送到请假或加班实际申请人
                {
                    model.MessageContent = string.Format("请您及时审批{0}的{1}单,时间从{2} {3}到{4} {5}, 总时长为{6}, {7}。",
                                                         agentUser.EnglishName,
                                                         order.IsOvertime() ? "加班" : "请假",
                                                         detail.StartDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.StartTime),
                                                         detail.EndDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.EndTime),
                                                         Math.Abs((sbyte)detail.IOHours),
                                                         recipient == null ? "没有工作交接人。" : "把工作交接给了" + recipient.EnglishName
                                                         );
                }
                else
                {
                    Log.Error("推送消息接收人不匹配。");
                    throw new KeyNotFoundException("推送消息接收人不匹配。");
                }
            }

            this._notificationService.Add(model, Global.IsProduction); //消息推送

            #endregion
        }