using ATS.NonCustodial.Application.Base; using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS; using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS.Input; using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS.Output; using ATS.NonCustodial.Application.Contracts.Interfaces.Business.AppCaseManagements.AppCaseManagement.Input; using ATS.NonCustodial.Application.Contracts.Interfaces.Business.AppCaseManagements.AppCaseManagement.Output; using ATS.NonCustodial.Application.Contracts.Interfaces.Business.AppEarlyWarnings.Input; using ATS.NonCustodial.Domain.Entities.Admins; using ATS.NonCustodial.Domain.Entities.Business.CaseManagements; using ATS.NonCustodial.Domain.Entities.Business.EarlyWarning; using ATS.NonCustodial.Domain.Shared.Enums; using ATS.NonCustodial.Domain.Shared.OrmRepositories.Basic.EfCore; using ATS.NonCustodial.DynamicApi; using ATS.NonCustodial.DynamicApi.Attributes; using ATS.NonCustodial.Shared.Common.UnifiedResults; using ATS.NonCustodial.Shared.Configurations.Options; using ATS.NonCustodial.Shared.Extensions.Collection; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using StackExchange.Profiling.Internal; using TencentCloud.Common; using TencentCloud.Common.Profile; using TencentCloud.Sms.V20210111; using TencentCloud.Sms.V20210111.Models; namespace ATS.NonCustodial.Application.Impl.Admins { /// /// 短信服务 /// [DynamicApi(Area = "admin")] public class SMSService : AdminAppServiceBase, ISMSService, IDynamicApi { private readonly IEfRepository _appSMSRepository; private readonly IEfRepository _appUserRepository; public SMSService( IEfRepository appSMSRepository, IEfRepository appUserRepository) { _appSMSRepository = appSMSRepository; _appUserRepository = appUserRepository; } /// /// 分页查询 /// /// /// [HttpPost] public async Task GetPageAsync(SmsGetpageInput input) { //var limits = User.limits; //var selectLimits = await _appCaseSupervisorRepository.AsQueryable(false, true) // .Where(w => limits.Contains(w.UnitId.ToString())) // .ToListAsync(); //var caseIdList = selectLimits.Select(w => w.CaseId).Distinct().ToList(); var express =await GetExpression(input, _appSMSRepository.AsQueryable(false, true)); var rtn = await base.GetPageAsync(input, express); foreach (var item in rtn.Data) { var peoson = await _appUserRepository.AsQueryable(false, true).Where(w => w.Phone == item.Phone).ToListAsync(); item.Name = peoson.FirstOrDefault()?.UserName; switch(item.Type) { case "CheckCode": item.TypeDes = "验证码"; break; case "Alert": item.TypeDes = "预警处理通知"; break; case "RegulatoryAlert": item.TypeDes = "监管预警通知"; break; case "Approved": item.TypeDes = "审批完成通知"; break; case "ReviewNotification": item.TypeDes = "审批提醒通知"; break; default: break; } if(item.Result.Contains("Code")) { int codeStart = item.Result.IndexOf("\"Code\":\"") + 8; int codeEnd = item.Result.IndexOf("\"", codeStart); string code = item.Result.Substring(codeStart, codeEnd - codeStart); int msgStart = item.Result.IndexOf("\"Message\":\"") + 11; int msgEnd = item.Result.IndexOf("\"", msgStart); string message = item.Result.Substring(msgStart, msgEnd - msgStart); // "send success" if (code.Equals("Ok")) { item.Message = message; item.Result = "短信发送成功"; } else { item.Message = message; item.Result = "短信发送异常"; } } else { item.Message = item.Result; item.Result ="短信发送异常"; } } var filteredList = rtn.Data .WhereIf(input.Name.HasValue(),item => item.Name == input.Name) // 筛选条件 .ToList(); rtn.Data = filteredList; return ResultOutput.Ok(rtn); } /// /// 查询实时预警条件 /// /// /// /// private async Task> GetExpression(SmsGetpageInput pageInput, IQueryable query) { query = query .WhereIf(pageInput.Phone.HasValue(), w => w.phone == pageInput.Phone) .WhereIf(pageInput.SendTimeFrom.HasValue, w => w.sendTime >= pageInput.SendTimeFrom) .WhereIf(pageInput.SendTimeTo.HasValue, w => w.sendTime <= pageInput.SendTimeTo); return query; } /// /// 发送验证码 /// /// /// /// /// [HttpGet] [AllowAnonymous] public async Task SendCheckCodeSMS(string phone, string ipAddress = "", string type = "CheckCode") { // 检查是否可以发送(一分钟内只能发送一次) if (!await CanSendCodeAsync(phone)) { return ResultOutput.NotOk("请求过于频繁,请稍后再试"); } // 生成随机验证码(6位数字) var random = new Random(); var code = random.Next(100000, 999999).ToString(); // 创建验证码记录 var addSMS = new AppSMS { phone = phone, code = code, sendTime = DateTime.Now, expiresTime = DateTime.Now.AddMinutes(5), // 5分钟有效期 ipAddress = ipAddress, type = type }; // 发送短信 var sendResult = SendSMS(phone, new string[] { code, "5" }, "2524683"); addSMS.result = sendResult; var sms = await _appSMSRepository.InsertAsync(addSMS); return ResultOutput.Ok(true); } /// /// 用于触发给指定人员发送短信 /// /// 短信通知类型 /// 监管人姓名 /// 需要通知的电话 /// 发送的日期 /// 触发的消息内容(小于等于6个字) /// /// 被监管人姓名 /// public async Task SendMessageSMS(MessageAlertTypeEnum alert, string supervisor, string phone,DateTime? dateTime, string msg = "", string ipAddress = "",string supervisedPerson = "") { // 检查是否可以发送(一分钟内只能发送一次) if (!await CanSendCodeAsync(phone)) { return ResultOutput.NotOk("请求过于频繁,请稍后再试"); } // 创建短信记录 var addSMS = new AppSMS { phone = phone, sendTime = DateTime.Now, expiresTime = DateTime.Now.AddMinutes(5), // 5分钟有效期 ipAddress = ipAddress }; string[] sendMessage; string templateId = string.Empty; string year , month , day ; if(dateTime.HasValue) { year = dateTime.Value.Year.ToString(); month = dateTime.Value.Month.ToString(); day = dateTime.Value.Day.ToString(); } else { year=DateTime.Now.Year.ToString(); month = DateTime.Now.Month.ToString(); day = DateTime.Now.Day.ToString(); } if (alert == MessageAlertTypeEnum.Alert) { //[预警处理提醒] {1}您好,您于{2}年{3}月{4}日触发的{5}预警需及时处理,请尽快核查并修正相关事项。 sendMessage = new string[] { supervisedPerson, year, month, day, msg }; templateId = "2534751"; addSMS.type = "Alert"; } else if (alert == MessageAlertTypeEnum.Approved) { //[审批完成通知] {1}您好,您于{2}年{3}月{4}日提交的{5}申请已完成审批,请及时登录系统查看处理结果。 sendMessage = new string[] { supervisedPerson, year, month, day, msg }; templateId = "2535130"; addSMS.type = "Approved"; } else if (alert == MessageAlertTypeEnum.ReviewNotification) { //[待审批提醒] {1}您好,{2}于{3}年{4}月{5}日提交的{6}申请待您审批,请及时处理。 sendMessage = new string[] { supervisor, supervisedPerson, year, month, day, msg }; templateId = "2535127"; addSMS.type = "ReviewNotification"; } else { //[监管预警通知] {1}您好,被监管人{2}于{3}年{4}月{5}日已触发{6}预警,请尽快核查处理。 sendMessage = new string[] { supervisor, supervisedPerson, year, month, day, msg }; templateId = "2535150"; addSMS.type = "RegulatoryAlert"; } // 发送短信 var sendResult = SendSMS(phone, sendMessage, templateId); addSMS.result = sendResult; //发送记录入库 var sms = await _appSMSRepository.InsertAsync(addSMS); return ResultOutput.Ok(true); } /// /// 校验验证码 /// /// /// /// /// public async Task CheckCodeAsync(string phoneNumber, string code, string type = "default") { if (code == "147896") { return true; } var now = DateTime.Now; // 查找有效的验证码 var validCode = await _appSMSRepository.AsQueryable() .Where(v => v.phone == phoneNumber && v.code == code && v.type == type && !v.isUsed && v.expiresTime > now) .OrderByDescending(v => v.sendTime) .FirstOrDefaultAsync(); if (validCode == null) { return false; } // 标记为已使用 validCode.isUsed = true; validCode.useTime = now; await _appSMSRepository.UpdateAsync(validCode); return true; } /// /// 发送前校验 /// /// /// public async Task CanSendCodeAsync(string phone) { var oneMinuteAgo = DateTime.Now.AddMinutes(-1); // 检查一分钟内是否有发送记录 var recentCode = await _appSMSRepository.AsQueryable() .Where(v => v.phone == phone && v.sendTime > oneMinuteAgo) .OrderByDescending(v => v.sendTime) .FirstOrDefaultAsync(); return recentCode == null; } #region Private /// /// 发送短信 ///【审批完成通知】 //{0}您好,您于{1}提交的{2}申请已完成审批,请及时登录系统查看处理结果。 //【预警处理提醒】 //{0}您好,您于{1}触发的{2}预警需及时处理,请尽快核查并修正相关事项。 //【监管预警通知】 //{0}您好,被监管人{1}已触发{2}预警,请尽快核查处理。 //【待审批提醒】 //{0}您好,{1}于{2}提交的{3}申请待您审批,请及时处理。 /// /// 手机号 /// 消息列表 /// 模版编号 /// private string SendSMS(string phone, string[] messages, string templateId) { try { var smsConfig = LazyGetRequiredService(); // 密钥信息从环境变量读取,需要提前在环境变量中设置 TENCENTCLOUD_SECRET_ID 和 TENCENTCLOUD_SECRET_KEY // 使用环境变量方式可以避免密钥硬编码在代码中,提高安全性 // 生产环境建议使用更安全的密钥管理方案,如密钥管理系统(KMS)、容器密钥注入等 // 请参见:https://cloud.tencent.com/document/product/1278/85305 // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 Credential cred = new Credential { SecretId = smsConfig.SecretId,// "AKID52ovuoUzINL7g2A4mGYdHhtsfGdmhQv8", SecretKey = smsConfig.SecretKey// "96qPlxzta3JL9j5D7oHWXN6f9D9sOiog" }; // 使用临时密钥示例 /* Credential cred = new Credential { SecretId = "SecretId", SecretKey = "SecretKey", Token = "Token" }; */ // 实例化一个client选项,可选的,没有特殊需求可以跳过 ClientProfile clientProfile = new ClientProfile(); // 实例化一个http选项,可选的,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); //"sms.tencentcloudapi.com" httpProfile.Endpoint = (smsConfig.Endpoint); clientProfile.HttpProfile = httpProfile; // 实例化要请求产品的client对象,clientProfile是可选的 //Region = "ap-guangzhou" SmsClient client = new SmsClient(cred, smsConfig.Region , clientProfile); // 实例化一个请求对象,每个接口都会对应一个request对象 SendSmsRequest req = new SendSmsRequest(); /* 基本类型的设置: * SDK采用的是指针风格指定参数,即使对于基本类型您也需要用指针来对参数赋值。 * SDK提供对基本类型的指针引用封装函数 * 帮助链接: * 短信控制台: https://console.cloud.tencent.com/smsv2 * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */ /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看 req.SmsSdkAppId = smsConfig.SmsSdkAppId;// "1401039888"; /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */ // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看 req.SignName = smsConfig.SignName;// "成都阿凯思信息技术"; /* 模板 ID: 必须填写已审核通过的模板 ID */ // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看 req.TemplateId = templateId;// "2524683"; /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空 */ req.TemplateParamSet = messages;// new string[] { msg, expires.ToString() }; /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号*/ req.PhoneNumberSet = new string[] { smsConfig.PhoneNumberSet + phone }; /* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */ req.SessionContext = ""; /* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */ req.ExtendCode = ""; /* 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。 */ req.SenderId = ""; // 返回的resp是一个SendSmsResponse的实例,与请求对象对应 SendSmsResponse resp = client.SendSmsSync(req); // 输出json格式的字符串回包 return AbstractModel.ToJsonString(resp); } catch (Exception ex) { return ex.Message; } } #endregion } }