From 7c36b64ac42645ba83c292d224a41f9cfb86be07 Mon Sep 17 00:00:00 2001
From: NoahLan <6995syu@163.com>
Date: Fri, 15 Mar 2024 09:58:46 +0800
Subject: [PATCH] =?UTF-8?q?wip:=20upms=20=E5=BC=80=E5=8F=91=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../NPin.Framework.Mapster.csproj | 2 +
.../Consts/ConfigConst.cs | 13 ++
.../Enums/SmsEnum.cs | 22 +++
.../Model/AliyunConfigModel.cs | 24 ++++
.../Model/SmsConfigModel.cs | 54 ++++++++
.../Model/TencentConfigModel.cs | 31 +++++
.../NPin.Framework.Upms.Domain.Shared.csproj | 3 -
.../Options/AliyunOptions.cs | 17 ---
.../Entities/AnnouncementEntity.cs | 32 +++++
.../Entities/ConfigEntity.cs | 34 +++++
.../Managers/RoleManager.cs | 15 ++
.../Managers/SmsManager.cs | 129 ++++++++++++++++++
.../NPinFrameworkUpmsDomainModule.cs | 4 -
.../Repositories/IConfigRepository.cs | 9 ++
.../NPin.Framework.Upms.Domain/Sms/ISms.cs | 11 ++
.../ConfigRepository.cs | 30 ++++
16 files changed, 406 insertions(+), 24 deletions(-)
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Consts/ConfigConst.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Enums/SmsEnum.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Model/AliyunConfigModel.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Model/SmsConfigModel.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Model/TencentConfigModel.cs
delete mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Options/AliyunOptions.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Entities/AnnouncementEntity.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Entities/ConfigEntity.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Managers/RoleManager.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Managers/SmsManager.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Repositories/IConfigRepository.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Sms/ISms.cs
create mode 100644 module/upms/NPin.Framework.Upms.SqlSugarCore/ConfigRepository.cs
diff --git a/framework/NPin.Framework.Mapster/NPin.Framework.Mapster.csproj b/framework/NPin.Framework.Mapster/NPin.Framework.Mapster.csproj
index 483ab23..cfa437a 100644
--- a/framework/NPin.Framework.Mapster/NPin.Framework.Mapster.csproj
+++ b/framework/NPin.Framework.Mapster/NPin.Framework.Mapster.csproj
@@ -3,6 +3,8 @@
+
+
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/Consts/ConfigConst.cs b/module/upms/NPin.Framework.Upms.Domain.Shared/Consts/ConfigConst.cs
new file mode 100644
index 0000000..9fcbd61
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain.Shared/Consts/ConfigConst.cs
@@ -0,0 +1,13 @@
+namespace NPin.Framework.Upms.Domain.Shared.Consts;
+
+public class ConfigConst
+{
+ ///
+ /// 系统配置前缀
+ ///
+ public const string SysConfigPrefix = "Sys";
+
+ public const string AliyunConfigKey = "Aliyun";
+ public const string TencentConfigKey = "Tencent";
+ public const string SmsConfigKey = "Sms";
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/Enums/SmsEnum.cs b/module/upms/NPin.Framework.Upms.Domain.Shared/Enums/SmsEnum.cs
new file mode 100644
index 0000000..2ef8710
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain.Shared/Enums/SmsEnum.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel;
+
+namespace NPin.Framework.Upms.Domain.Shared.Enums;
+
+///
+/// 短信提供商枚举
+///
+public enum SmsProviderEnum
+{
+ Aliyun,
+ Tencent
+}
+
+///
+/// 短信类型枚举
+///
+public enum SmsTypeEnum
+{
+ [Description("登录")] Login,
+ [Description("注册")] Register,
+ [Description("找回密码(重置密码)")] ResetPassword,
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/Model/AliyunConfigModel.cs b/module/upms/NPin.Framework.Upms.Domain.Shared/Model/AliyunConfigModel.cs
new file mode 100644
index 0000000..0bfa438
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain.Shared/Model/AliyunConfigModel.cs
@@ -0,0 +1,24 @@
+namespace NPin.Framework.Upms.Domain.Shared.Model;
+
+public class AliyunConfigModel
+{
+ ///
+ /// 访问密钥Key
+ ///
+ public string AccessKeyId { get; set; }
+
+ ///
+ /// 访问密钥
+ ///
+ public string AccessKeySecret { get; set; }
+
+ ///
+ /// 默认 区域ID
+ ///
+ public string RegionId { get; set; }
+
+ ///
+ /// 默认 短信访问 端点
+ ///
+ public string SmsEndpoint { get; set; } = "dysmsapi.aliyuncs.com";
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/Model/SmsConfigModel.cs b/module/upms/NPin.Framework.Upms.Domain.Shared/Model/SmsConfigModel.cs
new file mode 100644
index 0000000..34019fe
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain.Shared/Model/SmsConfigModel.cs
@@ -0,0 +1,54 @@
+using NPin.Framework.Upms.Domain.Shared.Enums;
+
+namespace NPin.Framework.Upms.Domain.Shared.Model;
+
+public class SmsConfigModel
+{
+ ///
+ /// 是否启用(总控)
+ ///
+ public bool Enabled { get; set; } = false;
+
+ ///
+ /// 设定集
+ ///
+ public Dictionary Settings { get; set; }
+}
+
+public class SmsSettings
+{
+ ///
+ /// 是否启用
+ ///
+ public bool Enabled { get; set; } = false;
+
+ ///
+ /// 服务提供商
+ ///
+ public SmsProviderEnum Provider { get; set; }
+
+ ///
+ /// 区域
+ ///
+ public string Region { get; set; }
+
+ ///
+ /// 短信访问 端点
+ ///
+ public string Endpoint { get; set; }
+
+ ///
+ /// 短信签名名称
+ ///
+ public string SignName { get; set; }
+
+ ///
+ /// 短信模板Code
+ ///
+ public string TemplateCode { get; set; }
+
+ ///
+ /// 过期时间,单位:秒
+ ///
+ public int Expires { get; set; }
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/Model/TencentConfigModel.cs b/module/upms/NPin.Framework.Upms.Domain.Shared/Model/TencentConfigModel.cs
new file mode 100644
index 0000000..6bc6739
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain.Shared/Model/TencentConfigModel.cs
@@ -0,0 +1,31 @@
+using Newtonsoft.Json;
+
+namespace NPin.Framework.Upms.Domain.Shared.Model;
+
+public class TencentConfigModel
+{
+ ///
+ /// 访问密钥Key
+ ///
+ public string SecretId { get; set; }
+
+ ///
+ /// 访问密钥
+ ///
+ public string SecretKey { get; set; }
+
+ ///
+ /// 默认区域
+ ///
+ public string Region { get; set; }
+
+ ///
+ /// 默认短信访问 端点
+ ///
+ public string SmsEndpoint { get; set; } = "sms.tencentcloudapi.com";
+
+ ///
+ /// 短信SdkAppId
+ ///
+ public string SmsSdkAppId { get; set; }
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/NPin.Framework.Upms.Domain.Shared.csproj b/module/upms/NPin.Framework.Upms.Domain.Shared/NPin.Framework.Upms.Domain.Shared.csproj
index 8fbf1da..86e96fc 100644
--- a/module/upms/NPin.Framework.Upms.Domain.Shared/NPin.Framework.Upms.Domain.Shared.csproj
+++ b/module/upms/NPin.Framework.Upms.Domain.Shared/NPin.Framework.Upms.Domain.Shared.csproj
@@ -7,8 +7,5 @@
-
-
-
diff --git a/module/upms/NPin.Framework.Upms.Domain.Shared/Options/AliyunOptions.cs b/module/upms/NPin.Framework.Upms.Domain.Shared/Options/AliyunOptions.cs
deleted file mode 100644
index 24de15c..0000000
--- a/module/upms/NPin.Framework.Upms.Domain.Shared/Options/AliyunOptions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace NPin.Framework.Upms.Domain.Shared.Options;
-
-///
-/// 阿里云SDK相关配置
-///
-public class AliyunOptions
-{
- public string AccessKeyId { get; set; }
- public string AccessKeySecret { get; set; }
- public AliyunSms Sms { get; set; }
-}
-
-public class AliyunSms
-{
- public string SignName { get; set; }
- public string TemplateCode { get; set; }
-}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/Entities/AnnouncementEntity.cs b/module/upms/NPin.Framework.Upms.Domain/Entities/AnnouncementEntity.cs
new file mode 100644
index 0000000..8d55e4b
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain/Entities/AnnouncementEntity.cs
@@ -0,0 +1,32 @@
+using NPin.Framework.SqlSugarCore.Abstractions.Data;
+using SqlSugar;
+using Volo.Abp.Auditing;
+using Volo.Abp.Domain.Entities;
+
+namespace NPin.Framework.Upms.Domain.Entities;
+
+[SugarTable("announcement", "系统公告表")]
+public class AnnouncementEntity : Entity, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
+{
+ [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
+
+ [SugarColumn(ColumnDescription = "公告标题")]
+ public string Title { get; set; }
+
+ [SugarColumn(ColumnDescription = "公告分类")]
+ public string Category { get; set; }
+
+ [SugarColumn(ColumnDescription = "公告行为")]
+ public string Action { get; set; }
+
+ [SugarColumn(ColumnDescription = "公告内容", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string Content { get; set; }
+
+ public bool IsDeleted { get; }
+ public DateTime CreationTime { get; }
+ public Guid? CreatorId { get; }
+ public DateTime? LastModificationTime { get; }
+ public Guid? LastModifierId { get; }
+ public int OrderNum { get; set; }
+ public bool IsEnabled { get; set; }
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/Entities/ConfigEntity.cs b/module/upms/NPin.Framework.Upms.Domain/Entities/ConfigEntity.cs
new file mode 100644
index 0000000..1a11029
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain/Entities/ConfigEntity.cs
@@ -0,0 +1,34 @@
+using Mapster;
+using NPin.Framework.SqlSugarCore.Abstractions.Data;
+using SqlSugar;
+using Volo.Abp.Auditing;
+using Volo.Abp.Domain.Entities;
+
+namespace NPin.Framework.Upms.Domain.Entities;
+
+[SugarTable("Config", "系统配置表")]
+[SugarIndex($"index_{nameof(Key)}", nameof(Key), OrderByType.Asc, true)]
+public class ConfigEntity : Entity, IEnabled, IOrderNum, ISoftDelete, IAuditedObject
+{
+ [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
+
+ [SugarColumn(ColumnDescription = "配置名称")]
+ public string Name { get; set; } = string.Empty;
+
+ [SugarColumn(ColumnDescription = "配置键")]
+ public string Key { get; set; } = string.Empty;
+
+ [SugarColumn(ColumnDescription = "配置值")]
+ public string Value { get; set; } = string.Empty;
+
+ [SugarColumn(ColumnDescription = "配置描述")]
+ public string? Remark { get; set; } = string.Empty;
+
+ public bool IsEnabled { get; set; }
+ public int OrderNum { get; set; }
+ public bool IsDeleted { get; }
+ public DateTime CreationTime { get; }
+ public Guid? CreatorId { get; }
+ public DateTime? LastModificationTime { get; }
+ public Guid? LastModifierId { get; }
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/Managers/RoleManager.cs b/module/upms/NPin.Framework.Upms.Domain/Managers/RoleManager.cs
new file mode 100644
index 0000000..446a558
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain/Managers/RoleManager.cs
@@ -0,0 +1,15 @@
+using NPin.Framework.SqlSugarCore.Abstractions;
+using NPin.Framework.Upms.Domain.Entities;
+using Volo.Abp.Domain.Services;
+
+namespace NPin.Framework.Upms.Domain.Managers;
+
+public class RoleManager: DomainService
+{
+ private ISqlSugarRepository _repository;
+
+ public RoleManager(ISqlSugarRepository repository)
+ {
+ _repository = repository;
+ }
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/Managers/SmsManager.cs b/module/upms/NPin.Framework.Upms.Domain/Managers/SmsManager.cs
new file mode 100644
index 0000000..2c698d1
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain/Managers/SmsManager.cs
@@ -0,0 +1,129 @@
+using AlibabaCloud.OpenApiClient.Models;
+using AlibabaCloud.SDK.Dysmsapi20170525;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using NPin.Framework.Upms.Domain.Repositories;
+using NPin.Framework.Upms.Domain.Shared.Enums;
+using NPin.Framework.Upms.Domain.Shared.Model;
+using NPin.Framework.Upms.Domain.Shared.Options;
+using TencentCloud.Common;
+using TencentCloud.Common.Profile;
+using TencentCloud.Sms.V20210111;
+using TencentCloud.Sms.V20210111.Models;
+using Volo.Abp.Caching;
+using Volo.Abp.Domain.Services;
+
+namespace NPin.Framework.Upms.Domain.Managers;
+
+public class SmsManager : DomainService, ISms
+{
+ private ILogger _logger;
+ private IConfigRepository _configRepository;
+ private IDistributedCache _cache;
+
+ public SmsManager(ILogger logger, IConfigRepository configRepository)
+ {
+ _logger = logger;
+ _configRepository = configRepository;
+ }
+
+ public async Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam)
+ {
+
+ try
+ {
+ var smsSettings = SmsOptions.Config[smsType];
+ if (!smsSettings.Enabled)
+ {
+ return;
+ }
+
+ switch (smsSettings.Provider)
+ {
+ case SmsProviderEnum.Aliyun:
+ await SendAliyunSmsAsync(smsSettings, phoneNumbers, templateParam);
+ break;
+ case SmsProviderEnum.Tencent:
+ await SendTencentSmsAsync(smsSettings, phoneNumbers, templateParam);
+ break;
+ default:
+ throw new Exception("未实现该服务提供商");
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"短信发送失败: {ex.Message}");
+ throw new UserFriendlyException($"短信发送失败: {ex.Message}");
+ }
+ }
+
+ private async Task SendTencentSmsAsync(SmsSettings settings, string phoneNumbers,
+ object templateParam)
+ {
+ var client = SmsClientProvider.CreateClient(TencentOptions, settings);
+
+ var sendSmsRequest = new SendSmsRequest
+ {
+ PhoneNumberSet = phoneNumbers.Split(','),
+ SignName = settings.SignName,
+ TemplateId = settings.TemplateCode,
+ TemplateParamSet = templateParam as string[]
+ };
+
+ var response = await client.SendSms(sendSmsRequest);
+ }
+
+ private async Task SendAliyunSmsAsync(SmsSettings settings, string phoneNumbers,
+ object templateParam)
+ {
+ var client = SmsClientProvider.CreateClient(AliyunOptions, settings);
+
+ var sendSmsRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest
+ {
+ PhoneNumbers = phoneNumbers,
+ SignName = settings.SignName,
+ TemplateCode = settings.TemplateCode,
+ TemplateParam = JsonConvert.SerializeObject(templateParam)
+ };
+
+ var response = await client.SendSmsAsync(sendSmsRequest);
+ }
+}
+
+public static class SmsClientProvider
+{
+ public static Client CreateClient(AliyunOptions options, SmsSettings settings)
+ {
+ var config = new Config()
+ {
+ AccessKeyId = options.AccessKeyId,
+ AccessKeySecret = options.AccessKeySecret,
+ Endpoint = settings.Endpoint,
+ RegionId = settings.RegionId,
+ };
+
+ return new Client(config);
+ }
+
+ public static SmsClient CreateClient(TencentOptions options, SmsSettings settings)
+ {
+ var cred = new Credential
+ {
+ SecretId = options.SecretId,
+ SecretKey = options.SecretKey,
+ };
+
+ var httpProfile = new HttpProfile
+ {
+ Endpoint = settings.Endpoint,
+ };
+
+ var clientProfile = new ClientProfile()
+ {
+ HttpProfile = httpProfile
+ };
+
+
+ return new SmsClient(cred, settings.RegionId, clientProfile);
+ }
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/NPinFrameworkUpmsDomainModule.cs b/module/upms/NPin.Framework.Upms.Domain/NPinFrameworkUpmsDomainModule.cs
index 4ab292e..6f41c0c 100644
--- a/module/upms/NPin.Framework.Upms.Domain/NPinFrameworkUpmsDomainModule.cs
+++ b/module/upms/NPin.Framework.Upms.Domain/NPinFrameworkUpmsDomainModule.cs
@@ -3,7 +3,6 @@ using NPin.Framework.Caching.FreeRedis;
using NPin.Framework.Upms.Domain.Authorization;
using NPin.Framework.Upms.Domain.OperLog;
using NPin.Framework.Upms.Domain.Shared;
-using NPin.Framework.Upms.Domain.Shared.Options;
using Volo.Abp.AspNetCore.SignalR;
using Volo.Abp.Caching;
using Volo.Abp.Domain;
@@ -29,8 +28,5 @@ public class NPinFrameworkUpmsDomainModule : AbpModule
opts.Filters.Add();
opts.Filters.Add();
});
-
- // 配置短信
- Configure(configuration.GetSection(nameof(AliyunOptions)));
}
}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/Repositories/IConfigRepository.cs b/module/upms/NPin.Framework.Upms.Domain/Repositories/IConfigRepository.cs
new file mode 100644
index 0000000..905eb32
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain/Repositories/IConfigRepository.cs
@@ -0,0 +1,9 @@
+using NPin.Framework.SqlSugarCore.Abstractions;
+using NPin.Framework.Upms.Domain.Entities;
+
+namespace NPin.Framework.Upms.Domain.Repositories;
+
+public interface IConfigRepository : ISqlSugarRepository
+{
+ Task GetSingleByKeyAsync(string key) where TDestination : new();
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.Domain/Sms/ISms.cs b/module/upms/NPin.Framework.Upms.Domain/Sms/ISms.cs
new file mode 100644
index 0000000..0ac1525
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.Domain/Sms/ISms.cs
@@ -0,0 +1,11 @@
+using NPin.Framework.Upms.Domain.Shared.Enums;
+
+namespace NPin.Framework.Upms.Domain.Managers;
+
+///
+/// 短信接口
+///
+public interface ISms
+{
+ Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam);
+}
\ No newline at end of file
diff --git a/module/upms/NPin.Framework.Upms.SqlSugarCore/ConfigRepository.cs b/module/upms/NPin.Framework.Upms.SqlSugarCore/ConfigRepository.cs
new file mode 100644
index 0000000..2d6de93
--- /dev/null
+++ b/module/upms/NPin.Framework.Upms.SqlSugarCore/ConfigRepository.cs
@@ -0,0 +1,30 @@
+using Newtonsoft.Json;
+using NPin.Framework.SqlSugarCore.Abstractions;
+using NPin.Framework.SqlSugarCore.Repositories;
+using NPin.Framework.Upms.Domain.Entities;
+using NPin.Framework.Upms.Domain.Repositories;
+using Volo.Abp.DependencyInjection;
+
+namespace NPin.Framework.Upms.SqlSugarCore;
+
+public class ConfigRepository : SqlSugarRepository, IConfigRepository, ITransientDependency
+{
+ public ConfigRepository(ISugarDbContextProvider sugarDbContextProvider) : base(
+ sugarDbContextProvider)
+ {
+ }
+
+ public async Task GetSingleByKeyAsync(string key) where TDestination : new()
+ {
+ var config = await DbQueryable
+ .Where(e => e.Key.Equals(key))
+ .FirstAsync();
+ if (config is null)
+ {
+ return new TDestination();
+ }
+
+ var ret = JsonConvert.DeserializeObject(config.Value);
+ return ret ?? new TDestination();
+ }
+}
\ No newline at end of file