From 8a94c46eed87a774a924972b589991136b5e84e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Tue, 10 Mar 2026 16:11:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E4=BD=8D=E8=AE=A4=E8=AF=81=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Logging/SysOperationLogService.cs | 2 +- .../Logging/SysSigninLogService.cs | 2 +- .../Merchant/Dtos/SubmitCertificationInput.cs | 43 +++++ .../Merchant/MerchantService.cs | 99 +++++++++- YD_Event.Application/Sms/AliyunSmsService.cs | 166 +++++++++++++++++ YD_Event.Application/YD_Event.Application.xml | 70 +++++++ YD_Event.Application/applicationsettings.json | 6 + YD_Event.Core/Entities/EventInfo.cs | 2 +- YD_Event.Core/Entities/SysSmsLog.cs | 63 +++++++ .../Extensions/ServiceCollectionExtension.cs | 1 + YD_Event.Core/Options/SmsOptions.cs | 38 ++++ YD_Event.Core/Sms/AliyunSmsService.cs | 174 ++++++++++++++++++ YD_Event.Core/YD_Event.Core.csproj | 1 + YD_Event.Core/YD_Event.Core.xml | 112 +++++++++++ 14 files changed, 775 insertions(+), 4 deletions(-) create mode 100644 YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs create mode 100644 YD_Event.Application/Sms/AliyunSmsService.cs create mode 100644 YD_Event.Core/Entities/SysSmsLog.cs create mode 100644 YD_Event.Core/Options/SmsOptions.cs create mode 100644 YD_Event.Core/Sms/AliyunSmsService.cs diff --git a/YD_Event.Application/Logging/SysOperationLogService.cs b/YD_Event.Application/Logging/SysOperationLogService.cs index 7f2d698..b38c837 100644 --- a/YD_Event.Application/Logging/SysOperationLogService.cs +++ b/YD_Event.Application/Logging/SysOperationLogService.cs @@ -1,4 +1,4 @@ -using YD_Event.Application.Logging.Dtos; +using YD_Event.Application.Logging.Dtos; namespace YD_Event.Application.Logging; /// diff --git a/YD_Event.Application/Logging/SysSigninLogService.cs b/YD_Event.Application/Logging/SysSigninLogService.cs index 66920e2..8338201 100644 --- a/YD_Event.Application/Logging/SysSigninLogService.cs +++ b/YD_Event.Application/Logging/SysSigninLogService.cs @@ -1,4 +1,4 @@ -using YD_Event.Application.Logging.Dtos; +using YD_Event.Application.Logging.Dtos; namespace YD_Event.Application.Logging; /// diff --git a/YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs b/YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs new file mode 100644 index 0000000..98853c0 --- /dev/null +++ b/YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace YD_Event.Application.Merchant.Dtos; + +public class SubmitCertificationInput +{ + /// + /// 单位名称 + /// + [Required(ErrorMessage = "单位名称不能为空")] + public string MerchantName { get; set; } + + /// + /// 统一社会信用代码 + /// + [Required(ErrorMessage = "统一社会信用代码不能为空")] + public string CreditCode { get; set; } + + /// + /// 营业执照图片URL + /// + [Required(ErrorMessage = "请上传营业执照")] + public string BusinessLicenseUrl { get; set; } + + /// + /// 地址 + /// + [Required(ErrorMessage = "地址不能为空")] + public string Address { get; set; } + + /// + /// 联系方式 + /// + [Required(ErrorMessage = "联系方式不能为空")] + [RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")] + public string ContactPhone { get; set; } + + /// + /// 验证码 + /// + [Required(ErrorMessage = "验证码不能为空")] + public string VerificationCode { get; set; } +} diff --git a/YD_Event.Application/Merchant/MerchantService.cs b/YD_Event.Application/Merchant/MerchantService.cs index 6cbf398..29dd58c 100644 --- a/YD_Event.Application/Merchant/MerchantService.cs +++ b/YD_Event.Application/Merchant/MerchantService.cs @@ -1,5 +1,7 @@ +using Microsoft.Extensions.Caching.Memory; using YD_Event.Application.Auth; using YD_Event.Application.Merchant.Dtos; +using YD_Event.Application.Sms; using YD_Event.Core.Entities; using YD_Event.Core.Enum; @@ -14,16 +16,111 @@ public class MerchantService : BaseService, ITr private readonly ISqlSugarRepository _userCouponRepository; private readonly AuthManager _authManager; private readonly IIdGenerator _idGenerator; + private readonly IMemoryCache _memoryCache; + private readonly AliyunSmsService _smsService; public MerchantService(ISqlSugarRepository repository, ISqlSugarRepository userCouponRepository, AuthManager authManager, - IIdGenerator idGenerator) : base(repository) + IIdGenerator idGenerator, + IMemoryCache memoryCache, + AliyunSmsService smsService) : base(repository) { _repository = repository; _userCouponRepository = userCouponRepository; _authManager = authManager; _idGenerator = idGenerator; + _memoryCache = memoryCache; + _smsService = smsService; + } + + /// + /// 发送验证码 + /// + [DisplayName("发送验证码")] + [HttpPost("sendVerificationCode")] + [AllowAnonymous] + public async Task SendVerificationCode([FromQuery] string phone) + { + if (string.IsNullOrWhiteSpace(phone) || !System.Text.RegularExpressions.Regex.IsMatch(phone, @"^1[3456789]\d{9}$")) + throw Oops.Bah("手机号格式不正确"); + + // 生成6位验证码 + var code = new Random().Next(100000, 999999).ToString(); + + // 存入缓存,有效期5分钟 + _memoryCache.Set($"verification_code_{phone}", code, TimeSpan.FromMinutes(5)); + + // 发送短信 + await _smsService.SendVerificationCodeAsync(phone, code); + } + + /// + /// 提交单位认证 + /// + [DisplayName("提交单位认证")] + [HttpPost("submitCertification")] + public async Task SubmitCertification(SubmitCertificationInput input) + { + // 验证验证码 + if (!_memoryCache.TryGetValue($"verification_code_{input.ContactPhone}", out string? cachedCode) || cachedCode != input.VerificationCode) + { + throw Oops.Bah("验证码错误或已过期"); + } + + // 获取当前用户关联的商户信息 + var userId = _authManager.UserId; + var merchant = await _repository.GetFirstAsync(m => m.CreatedUserId == userId); + + if (merchant == null) + { + // 新增商户 + merchant = new YD_Event.Core.Entities.Merchant + { + Id = _idGenerator.NextId(), + MerchantName = input.MerchantName, + CreditCode = input.CreditCode, + BusinessLicenseUrl = input.BusinessLicenseUrl, + Address = input.Address, + ContactPhone = input.ContactPhone, + BankName = "", // 默认为空,后续完善 + AccountNumber = "", // 默认为空,后续完善 + AuditStatus = AuditStatus.PendingAudit, // 待审核 + Status = AvailabilityStatus.Enable, + CreatedUserId = userId, + CreatedTime = DateTime.Now + }; + await _repository.InsertAsync(merchant); + } + else + { + // 更新商户信息 + merchant.MerchantName = input.MerchantName; + merchant.CreditCode = input.CreditCode; + merchant.BusinessLicenseUrl = input.BusinessLicenseUrl; + merchant.Address = input.Address; + merchant.ContactPhone = input.ContactPhone; + merchant.AuditStatus = AuditStatus.PendingAudit; // 重新提交后变为待审核 + merchant.UpdatedUserId = userId; + merchant.UpdatedTime = DateTime.Now; + + await _repository.UpdateAsync(merchant); + } + + // 清除验证码 + _memoryCache.Remove($"verification_code_{input.ContactPhone}"); + } + + /// + /// 获取我的认证信息 + /// + [DisplayName("获取我的认证信息")] + [HttpGet("myCertification")] + public async Task GetMyCertification() + { + var userId = _authManager.UserId; + var merchant = await _repository.GetFirstAsync(m => m.CreatedUserId == userId); + return merchant; } /// diff --git a/YD_Event.Application/Sms/AliyunSmsService.cs b/YD_Event.Application/Sms/AliyunSmsService.cs new file mode 100644 index 0000000..7aa6ce2 --- /dev/null +++ b/YD_Event.Application/Sms/AliyunSmsService.cs @@ -0,0 +1,166 @@ +using AlibabaCloud.OpenApiClient.Models; +using AlibabaCloud.SDK.Dysmsapi20170525; +using AlibabaCloud.SDK.Dysmsapi20170525.Models; +using Furion.DependencyInjection; +using Furion.FriendlyException; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using SqlSugar; +using Tea; +using YD_Event.Core.Entities; +using YD_Event.Core.Options; + +namespace YD_Event.Application.Sms; + +/// +/// 阿里云短信服务实现 +/// +public class AliyunSmsService : ITransient +{ + private readonly SmsOptions _options; + private readonly ILogger _logger; + private readonly ISqlSugarRepository _smsLogRepository; + private AlibabaCloud.SDK.Dysmsapi20170525.Client _client; + + public AliyunSmsService(IOptions options, + ILogger logger, + ISqlSugarRepository smsLogRepository) + { + _options = options.Value; + _logger = logger; + _smsLogRepository = smsLogRepository; + InitClient(); + } + + /// + /// 初始化阿里云短信客户端 + /// + private void InitClient() + { + if (string.IsNullOrWhiteSpace(_options.AccessKeyId) || string.IsNullOrWhiteSpace(_options.AccessKeySecret)) + { + _logger.LogWarning("阿里云短信配置缺失:AccessKeyId或AccessKeySecret为空"); + return; + } + + var config = new Config + { + AccessKeyId = _options.AccessKeyId, + AccessKeySecret = _options.AccessKeySecret, + Endpoint = _options.Endpoint + }; + + try + { + _client = new AlibabaCloud.SDK.Dysmsapi20170525.Client(config); + } + catch (Exception ex) + { + _logger.LogError(ex, "阿里云短信客户端初始化失败"); + } + } + + /// + /// 发送验证码短信 + /// + public async Task SendVerificationCodeAsync(string phone, string code) + { + // 校验配置 + ValidateConfig(); + + if (string.IsNullOrWhiteSpace(_options.VerificationCodeTemplateCode)) + throw Oops.Bah("短信验证码模板未配置"); + + var param = JsonConvert.SerializeObject(new { code = code }); + await SendSmsAsync(phone, _options.VerificationCodeTemplateCode, param); + } + + /// + /// 发送短信核心方法 + /// + public async Task SendSmsAsync(string phone, string templateCode, string templateParam) + { + // 1. 参数校验 + if (string.IsNullOrWhiteSpace(phone)) throw Oops.Bah("手机号不能为空"); + if (string.IsNullOrWhiteSpace(templateCode)) throw Oops.Bah("短信模板不能为空"); + + ValidateConfig(); + + // 2. 构造请求 + var request = new SendSmsRequest + { + PhoneNumbers = phone, + SignName = _options.SignName, + TemplateCode = templateCode, + TemplateParam = templateParam + }; + + // 3. 准备日志实体 + var log = new SysSmsLog + { + Phone = phone, + TemplateCode = templateCode, + TemplateParam = templateParam, + CreatedTime = DateTime.Now + }; + + try + { + // 4. 发送请求 + var response = await _client.SendSmsAsync(request); + + // 5. 处理响应 + log.ResponseCode = response.Body.Code; + log.ResponseMessage = response.Body.Message; + log.RequestId = response.Body.RequestId; + log.Success = response.Body.Code == "OK"; + + if (!log.Success) + { + _logger.LogWarning($"短信发送失败:{phone}, Code: {response.Body.Code}, Message: {response.Body.Message}"); + throw Oops.Bah($"短信发送失败:{response.Body.Message}"); + } + } + catch (TeaException error) + { + // 阿里云SDK异常 + log.Success = false; + log.Exception = $"Code: {error.Code}, Message: {error.Message}, Data: {JsonConvert.SerializeObject(error.Data)}"; + _logger.LogError(error, "阿里云短信发送异常"); + throw Oops.Bah("短信服务异常,请稍后重试"); + } + catch (Exception ex) + { + // 其他异常(网络等) + log.Success = false; + log.Exception = ex.Message; + _logger.LogError(ex, "短信发送未知异常"); + throw Oops.Bah("短信发送失败,请检查网络或联系管理员"); + } + finally + { + // 6. 日志持久化 + await _smsLogRepository.InsertAsync(log); + } + } + + /// + /// 校验配置是否有效 + /// + public void ValidateConfig() + { + if (_client == null) + { + InitClient(); + if (_client == null) + throw Oops.Bah("短信服务未初始化,请检查AccessKeyId和AccessKeySecret配置"); + } + + if (string.IsNullOrWhiteSpace(_options.SignName)) + throw Oops.Bah("短信签名(SignName)未配置"); + + if (string.IsNullOrWhiteSpace(_options.VerificationCodeTemplateCode)) + throw Oops.Bah("验证码模板(VerificationCodeTemplateCode)未配置"); + } +} diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index c73f5eb..8df2406 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -2508,6 +2508,36 @@ 商户审核输入 + + + 单位名称 + + + + + 统一社会信用代码 + + + + + 营业执照图片URL + + + + + 地址 + + + + + 联系方式 + + + + + 验证码 + + 主键Id @@ -2518,6 +2548,21 @@ 商户管理 + + + 发送验证码 + + + + + 提交单位认证 + + + + + 获取我的认证信息 + + 商户分页查询 @@ -3581,6 +3626,31 @@ + + + 阿里云短信服务实现 + + + + + 初始化阿里云短信客户端 + + + + + 发送验证码短信 + + + + + 发送短信核心方法 + + + + + 校验配置是否有效 + + 姓名 diff --git a/YD_Event.Application/applicationsettings.json b/YD_Event.Application/applicationsettings.json index 8bf8e50..b89212f 100644 --- a/YD_Event.Application/applicationsettings.json +++ b/YD_Event.Application/applicationsettings.json @@ -139,5 +139,11 @@ // } //] } + }, + // 阿里云短信配置 + "ALiYunSMS": { + "Endpoint": "dysmsapi.aliyuncs.com", + "Sign": "oVpeH1PpDUnWTcBrUSSYkQNS4Fex8Y", + "Template": "SMS_147140268" } } \ No newline at end of file diff --git a/YD_Event.Core/Entities/EventInfo.cs b/YD_Event.Core/Entities/EventInfo.cs index 48fcd75..09dfa98 100644 --- a/YD_Event.Core/Entities/EventInfo.cs +++ b/YD_Event.Core/Entities/EventInfo.cs @@ -1,4 +1,4 @@ -using SqlSugar; +using SqlSugar; using YD_Event.Core.Enum; namespace YD_Event.Core.Entities; diff --git a/YD_Event.Core/Entities/SysSmsLog.cs b/YD_Event.Core/Entities/SysSmsLog.cs new file mode 100644 index 0000000..cf0df0e --- /dev/null +++ b/YD_Event.Core/Entities/SysSmsLog.cs @@ -0,0 +1,63 @@ +using SqlSugar; +using YD_Event.Core.Enum; + +namespace YD_Event.Core.Entities; + +/// +/// 短信发送日志 +/// +[SugarTable("SysSmsLog")] +public class SysSmsLog : Entity, ICreatedTime +{ + /// + /// 接收手机号 + /// + [SugarColumn(Length = 20)] + public string Phone { get; set; } + + /// + /// 短信模板Code + /// + [SugarColumn(Length = 50)] + public string TemplateCode { get; set; } + + /// + /// 模板参数 + /// + [SugarColumn(Length = 512, IsNullable = true)] + public string TemplateParam { get; set; } + + /// + /// 发送状态(成功/失败) + /// + public bool Success { get; set; } + + /// + /// 响应代码 + /// + [SugarColumn(Length = 50, IsNullable = true)] + public string ResponseCode { get; set; } + + /// + /// 响应消息 + /// + [SugarColumn(Length = 512, IsNullable = true)] + public string ResponseMessage { get; set; } + + /// + /// 请求ID + /// + [SugarColumn(Length = 128, IsNullable = true)] + public string RequestId { get; set; } + + /// + /// 异常信息 + /// + [SugarColumn(ColumnDataType = "text", IsNullable = true)] + public string Exception { get; set; } + + /// + /// 发送时间 + /// + public DateTime CreatedTime { get; set; } +} diff --git a/YD_Event.Core/Extensions/ServiceCollectionExtension.cs b/YD_Event.Core/Extensions/ServiceCollectionExtension.cs index 8c53844..8f2bf82 100644 --- a/YD_Event.Core/Extensions/ServiceCollectionExtension.cs +++ b/YD_Event.Core/Extensions/ServiceCollectionExtension.cs @@ -14,6 +14,7 @@ public static class ServiceCollectionExtension service.AddConfigurableOptions(); service.AddConfigurableOptions(); service.AddConfigurableOptions(); + service.AddConfigurableOptions(); return service; } } \ No newline at end of file diff --git a/YD_Event.Core/Options/SmsOptions.cs b/YD_Event.Core/Options/SmsOptions.cs new file mode 100644 index 0000000..7753c2a --- /dev/null +++ b/YD_Event.Core/Options/SmsOptions.cs @@ -0,0 +1,38 @@ +using Furion.ConfigurableOptions; +using Microsoft.Extensions.Configuration; + +namespace YD_Event.Core.Options; + +/// +/// 短信配置选项 +/// +[OptionsSettings("ALiYunSMS")] +public class SmsOptions : IConfigurableOptions +{ + /// + /// AccessKeyId + /// + public string AccessKeyId { get; set; } + + /// + /// AccessKeySecret + /// + public string AccessKeySecret { get; set; } + + /// + /// 短信签名 + /// + [ConfigurationKeyName("Sign")] + public string SignName { get; set; } + + /// + /// 验证码模板Code + /// + [ConfigurationKeyName("Template")] + public string VerificationCodeTemplateCode { get; set; } + + /// + /// 短信API Endpoint + /// + public string Endpoint { get; set; } = "dysmsapi.aliyuncs.com"; +} diff --git a/YD_Event.Core/Sms/AliyunSmsService.cs b/YD_Event.Core/Sms/AliyunSmsService.cs new file mode 100644 index 0000000..f0e7580 --- /dev/null +++ b/YD_Event.Core/Sms/AliyunSmsService.cs @@ -0,0 +1,174 @@ +using AlibabaCloud.OpenApiClient.Models; +using AlibabaCloud.SDK.Dysmsapi20170525; +using AlibabaCloud.SDK.Dysmsapi20170525.Models; +using Furion.DependencyInjection; +using Furion.FriendlyException; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using SqlSugar; +using System.Threading.Tasks; +using Tea; +using YD_Event.Core.Entities; +using YD_Event.Core.Options; + +namespace YD_Event.Application.Sms; + +/// +/// 阿里云短信服务实现 +/// +public class AliyunSmsService : ITransient +{ + private readonly SmsOptions _options; + private readonly ILogger _logger; + private readonly ISqlSugarRepository _smsLogRepository; + private Client _client; + + public AliyunSmsService(IOptions options, + ILogger logger, + ISqlSugarRepository smsLogRepository) + { + _options = options.Value; + _logger = logger; + _smsLogRepository = smsLogRepository; + InitClient(); + } + + /// + /// 初始化阿里云短信客户端 + /// + private void InitClient() + { + if (string.IsNullOrWhiteSpace(_options.AccessKeyId) || string.IsNullOrWhiteSpace(_options.AccessKeySecret)) + { + _logger.LogWarning("阿里云短信配置缺失:AccessKeyId或AccessKeySecret为空"); + return; + } + + var config = new Config + { + AccessKeyId = _options.AccessKeyId, + AccessKeySecret = _options.AccessKeySecret, + Endpoint = _options.Endpoint + }; + + try + { + _client = new Client(config); + } + catch (Exception ex) + { + _logger.LogError(ex, "阿里云短信客户端初始化失败"); + } + } + + /// + /// 发送验证码短信 + /// + /// 手机号 + /// 验证码 + /// + public async Task SendVerificationCodeAsync(string phone, string code) + { + // 校验配置 + ValidateConfig(); + + if (string.IsNullOrWhiteSpace(_options.VerificationCodeTemplateCode)) + throw Oops.Bah("短信验证码模板未配置"); + + var param = JsonConvert.SerializeObject(new { code = code }); + await SendSmsAsync(phone, _options.VerificationCodeTemplateCode, param); + } + + /// + /// 发送自定义短信 + /// + /// 手机号 + /// 模板编码 + /// 模板参数JSON字符串 + /// + public async Task SendSmsAsync(string phone, string templateCode, string templateParam) + { + // 1. 参数校验 + if (string.IsNullOrWhiteSpace(phone)) throw Oops.Bah("手机号不能为空"); + if (string.IsNullOrWhiteSpace(templateCode)) throw Oops.Bah("短信模板不能为空"); + + ValidateConfig(); + + // 2. 构造请求 + var request = new SendSmsRequest + { + PhoneNumbers = phone, + SignName = _options.SignName, + TemplateCode = templateCode, + TemplateParam = templateParam + }; + + // 3. 准备日志实体 + var log = new SysSmsLog + { + Phone = phone, + TemplateCode = templateCode, + TemplateParam = templateParam, + CreatedTime = DateTime.Now + }; + + try + { + // 4. 发送请求 + var response = await _client.SendSmsAsync(request); + + // 5. 处理响应 + log.ResponseCode = response.Body.Code; + log.ResponseMessage = response.Body.Message; + log.RequestId = response.Body.RequestId; + log.Success = response.Body.Code == "OK"; + + if (!log.Success) + { + _logger.LogWarning($"短信发送失败:{phone}, Code: {response.Body.Code}, Message: {response.Body.Message}"); + throw Oops.Bah($"短信发送失败:{response.Body.Message}"); + } + } + catch (TeaException error) + { + // 阿里云SDK异常 + log.Success = false; + log.Exception = $"Code: {error.Code}, Message: {error.Message}, Data: {JsonConvert.SerializeObject(error.Data)}"; + _logger.LogError(error, "阿里云短信发送异常"); + throw Oops.Bah("短信服务异常,请稍后重试"); + } + catch (Exception ex) + { + // 其他异常(网络等) + log.Success = false; + log.Exception = ex.Message; + _logger.LogError(ex, "短信发送未知异常"); + throw Oops.Bah("短信发送失败,请检查网络或联系管理员"); + } + finally + { + // 6. 日志持久化 + await _smsLogRepository.InsertAsync(log); + } + } + + /// + /// 校验短信配置 + /// + public void ValidateConfig() + { + if (_client == null) + { + InitClient(); + if (_client == null) + throw Oops.Bah("短信服务未初始化,请检查AccessKeyId和AccessKeySecret配置"); + } + + if (string.IsNullOrWhiteSpace(_options.SignName)) + throw Oops.Bah("短信签名(SignName)未配置"); + + if (string.IsNullOrWhiteSpace(_options.VerificationCodeTemplateCode)) + throw Oops.Bah("验证码模板(VerificationCodeTemplateCode)未配置"); + } +} diff --git a/YD_Event.Core/YD_Event.Core.csproj b/YD_Event.Core/YD_Event.Core.csproj index 9e9ef6b..a3f52e8 100644 --- a/YD_Event.Core/YD_Event.Core.csproj +++ b/YD_Event.Core/YD_Event.Core.csproj @@ -8,6 +8,7 @@ + diff --git a/YD_Event.Core/YD_Event.Core.xml b/YD_Event.Core/YD_Event.Core.xml index ae43f72..e0dab36 100644 --- a/YD_Event.Core/YD_Event.Core.xml +++ b/YD_Event.Core/YD_Event.Core.xml @@ -3366,6 +3366,56 @@ 创建时间 + + + 短信发送日志 + + + + + 接收手机号 + + + + + 短信模板Code + + + + + 模板参数 + + + + + 发送状态(成功/失败) + + + + + 响应代码 + + + + + 响应消息 + + + + + 请求ID + + + + + 异常信息 + + + + + 发送时间 + + 系统用户表 @@ -4156,6 +4206,36 @@ 是否启用对象存储(不启用将存储至站点目录) + + + 短信配置选项 + + + + + AccessKeyId + + + + + AccessKeySecret + + + + + 短信签名 + + + + + 验证码模板Code + + + + + 短信API Endpoint + + 雪花id配置 @@ -4196,6 +4276,38 @@ 子选项 + + + 阿里云短信服务实现 + + + + + 初始化阿里云短信客户端 + + + + + 发送验证码短信 + + 手机号 + 验证码 + + + + + 发送自定义短信 + + 手机号 + 模板编码 + 模板参数JSON字符串 + + + + + 校验短信配置 + + 缓存