Compare commits
60 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e864eecb3d | 4 weeks ago |
|
|
d45a891f41 | 1 month ago |
|
|
a48ae2e79a | 2 months ago |
|
|
e1799fc3b8 | 2 months ago |
|
|
4fb3f4ae20 | 2 months ago |
|
|
cdec9117c6 | 2 months ago |
|
|
9612645071 | 2 months ago |
|
|
c384f24cc1 | 2 months ago |
|
|
a40f4beea1 | 2 months ago |
|
|
5ee99b0d21 | 2 months ago |
|
|
1d2253a523 | 2 months ago |
|
|
4b39b2c425 | 2 months ago |
|
|
60f16c0469 | 2 months ago |
|
|
ff6d3b8c7b | 2 months ago |
|
|
bb106ceee4 | 2 months ago |
|
|
925a4486b9 | 2 months ago |
|
|
da940af097 | 2 months ago |
|
|
8fa25031cd | 2 months ago |
|
|
606b06b05f | 2 months ago |
|
|
0b5a5b85fa | 2 months ago |
|
|
72ed50cb47 | 3 months ago |
|
|
7e6de39fa8 | 3 months ago |
|
|
8c38a8e2e5 | 3 months ago |
|
|
cb5071bffb | 3 months ago |
|
|
474d481b5e | 3 months ago |
|
|
24ea9e097e | 3 months ago |
|
|
0d3c190ad7 | 3 months ago |
|
|
55d0c24d99 | 3 months ago |
|
|
bbac947787 | 3 months ago |
|
|
157056efb8 | 3 months ago |
|
|
82264d99fc | 3 months ago |
|
|
a86a5aa087 | 3 months ago |
|
|
f7764bf88a | 3 months ago |
|
|
639a6fb3a4 | 3 months ago |
|
|
1560949db5 | 3 months ago |
|
|
5b924548c0 | 3 months ago |
|
|
109a0ceeac | 3 months ago |
|
|
1b878776b8 | 3 months ago |
|
|
136ff1f656 | 3 months ago |
|
|
94f5feaac8 | 3 months ago |
|
|
241450ddf1 | 3 months ago |
|
|
46a26db1f8 | 3 months ago |
|
|
64c5ca915e | 3 months ago |
|
|
496946447e | 3 months ago |
|
|
8b48feaba4 | 3 months ago |
|
|
9fa91adcfc | 3 months ago |
|
|
70e44379a2 | 3 months ago |
|
|
f5472e4fea | 3 months ago |
|
|
848fd84f84 | 3 months ago |
|
|
c80799db6d | 3 months ago |
|
|
e67dd34993 | 3 months ago |
|
|
ceb68d34e8 | 3 months ago |
|
|
b8808ffee1 | 3 months ago |
|
|
ec3758b0bf | 3 months ago |
|
|
33214a4252 | 3 months ago |
|
|
a392df1ccb | 3 months ago |
|
|
30b6a27ec5 | 3 months ago |
|
|
3b4e13dbd2 | 3 months ago |
|
|
c2d3a2f012 | 3 months ago |
|
|
819d13915c | 3 months ago |
77 changed files with 3200 additions and 29874 deletions
@ -0,0 +1,35 @@
|
||||
{ |
||||
"version": "0.2.0", |
||||
"configurations": [ |
||||
{ |
||||
// 使用 IntelliSense 找出 C# 调试存在哪些属性 |
||||
// 将悬停用于现有属性的说明 |
||||
// 有关详细信息,请访问 https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md。 |
||||
"name": ".NET Core Launch (web)", |
||||
"type": "coreclr", |
||||
"request": "launch", |
||||
"preLaunchTask": "build", |
||||
// 如果已更改目标框架,请确保更新程序路径。 |
||||
"program": "${workspaceFolder}/src/4.apps/ATS.NonCustodial.Admin.Api/bin/Debug/net9.0/ATS.NonCustodial.Admin.Api.dll", |
||||
"args": [], |
||||
"cwd": "${workspaceFolder}/src/4.apps/ATS.NonCustodial.Admin.Api", |
||||
"stopAtEntry": false, |
||||
// 启用在启动 ASP.NET Core 时启动 Web 浏览器。有关详细信息: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser |
||||
"serverReadyAction": { |
||||
"action": "openExternally", |
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)" |
||||
}, |
||||
"env": { |
||||
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
}, |
||||
"sourceFileMap": { |
||||
"/Views": "${workspaceFolder}/Views" |
||||
} |
||||
}, |
||||
{ |
||||
"name": ".NET Core Attach", |
||||
"type": "coreclr", |
||||
"request": "attach" |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,41 @@
|
||||
{ |
||||
"version": "2.0.0", |
||||
"tasks": [ |
||||
{ |
||||
"label": "build", |
||||
"command": "dotnet", |
||||
"type": "process", |
||||
"args": [ |
||||
"build", |
||||
"${workspaceFolder}/ATS.NonCustodial.Admin.sln", |
||||
"/property:GenerateFullPaths=true", |
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign" |
||||
], |
||||
"problemMatcher": "$msCompile" |
||||
}, |
||||
{ |
||||
"label": "publish", |
||||
"command": "dotnet", |
||||
"type": "process", |
||||
"args": [ |
||||
"publish", |
||||
"${workspaceFolder}/ATS.NonCustodial.Admin.sln", |
||||
"/property:GenerateFullPaths=true", |
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign" |
||||
], |
||||
"problemMatcher": "$msCompile" |
||||
}, |
||||
{ |
||||
"label": "watch", |
||||
"command": "dotnet", |
||||
"type": "process", |
||||
"args": [ |
||||
"watch", |
||||
"run", |
||||
"--project", |
||||
"${workspaceFolder}/ATS.NonCustodial.Admin.sln" |
||||
], |
||||
"problemMatcher": "$msCompile" |
||||
} |
||||
] |
||||
} |
||||
@ -1,3 +1,159 @@
|
||||
# NonDetainmentSoft |
||||
|
||||
非羁押人员管理系统 |
||||
|
||||
## 1. 项目概述 |
||||
ATS.NonCustodial.Admin 是一个基于 .NET 9.0 开发的后端管理系统,主要用于非监禁人员管理业务,提供案件管理、业务申请、设备管理等功能模块。系统采用分层架构设计,具有良好的扩展性和可维护性。 |
||||
|
||||
## 2. 技术栈 |
||||
- 开发框架 :.NET 9.0 |
||||
- ORM框架 :Entity Framework Core 9.0.8 |
||||
- 数据库 :MySQL |
||||
- 身份认证 :JWT / IdentityServer4 |
||||
- 依赖注入 :Autofac |
||||
- 实时通信 :SignalR |
||||
- 任务调度 :Quartz |
||||
- API文档 :Swagger |
||||
- 缓存 :Redis |
||||
- 日志 :Serilog |
||||
- 数据映射 :AutoMapper |
||||
## 3. 项目架构 |
||||
项目采用典型的分层架构设计,各层职责明确: |
||||
|
||||
``` |
||||
src/ |
||||
├── 1.datas/ # 数据层 |
||||
│ ├── ATS.NonCustodial.DbMigrations/ # 数据库迁移 |
||||
│ ├── ATS.NonCustodial.Domain/ # 领域模型 |
||||
│ └── ATS.NonCustodial.EntityFrameworkCore/ # EF Core 实现 |
||||
├── 2.services/ # 业务服务层 |
||||
│ └── ATS.NonCustodial.Application/ # 应用服务实现 |
||||
├── 3.contracts/ # 接口层 |
||||
│ └── ATS.NonCustodial.Application.Contracts/ # 服务接口定义 |
||||
├── 4.apps/ # 应用层 |
||||
│ └── ATS.NonCustodial.Admin.Api/ # Web API 应用 |
||||
└── 5.shared/ # 共享层 |
||||
├── ATS.NonCustodial.Admin.Jobs/ # 定时任务 |
||||
├── ATS.NonCustodial.AdminUi/ # 管理UI组件 |
||||
├── ATS.NonCustodial.AuditLogging/ # 审计日志 |
||||
├── ATS.NonCustodial.Domain.Shared/ # 领域共享 |
||||
├── ATS.NonCustodial.DynamicApi/ # 动态API |
||||
└── ATS.NonCustodial.Shared/ # 通用工具 |
||||
``` |
||||
|
||||
## 4. 核心模块 |
||||
### 4.1 案件管理模块 |
||||
负责非监禁人员案件的创建、查询、更新和删除,包含案件信息、监管人员和被监管人员管理。 |
||||
|
||||
主要实体: |
||||
|
||||
- AppCaseManagement :案件管理实体 |
||||
- AppCaseSupervisor :监管人员实体 |
||||
- AppCaseSupervisedPerson :被监管人员实体 |
||||
### 4.2 业务申请模块 |
||||
处理被监管人员的各类业务申请,如请假、外出活动等,包含申请提交、审核、统计等功能。 |
||||
|
||||
主要服务: |
||||
|
||||
- AppBusinessApplicationService :业务申请服务 |
||||
- 提供申请创建、查询、审核、统计等功能 |
||||
### 4.3 设备管理模块 |
||||
管理与被监管人员关联的电子设备,如定位设备等。 |
||||
|
||||
主要服务: |
||||
|
||||
- AppDeviceManagementService :设备管理服务 |
||||
### 4.4 用户权限管理 |
||||
处理系统用户、角色和权限的管理。 |
||||
|
||||
主要服务: |
||||
|
||||
- RoleService :角色管理服务 |
||||
- UserService :用户管理服务 |
||||
### 4.5 文件管理模块 |
||||
提供文件上传、下载、管理功能,支持多种文件类型。 |
||||
|
||||
主要配置: |
||||
|
||||
- UploadConfigConfiguration :文件上传配置,支持头像、图片、资料等类型 |
||||
## 5. 系统配置 |
||||
### 5.1 数据库配置 |
||||
系统使用 MySQL 数据库,配置位于 appsettings.json 的 ConnectionStringsConfiguration 节点: |
||||
|
||||
``` |
||||
"ConnectionStringsConfiguration": { |
||||
"AdminAuditLogDbConnection": "Server=localhost;database=fsl_cs;uid=root;pwd=sa@admin;...", |
||||
"AdminDbConnection": "Server=localhost;database=fsl_cs;uid=root;pwd=sa@admin;..." |
||||
}, |
||||
"DatabaseProviderConfiguration": { |
||||
"ProviderType": "MySql" |
||||
} |
||||
``` |
||||
|
||||
### 5.2 身份认证配置 |
||||
支持 JWT 和 IdentityServer4 两种认证方式,JWT 配置如下: |
||||
|
||||
``` |
||||
"JwtConfiguration": { |
||||
"Issuer": "http://127.0.0.1:8006", |
||||
"Audience": "http://127.0.0.1:8006", |
||||
"SymmetricSecurityKey": "ertJKl#521*a@790asD&1#0123456789", |
||||
"Expires": 1440, |
||||
"RefreshTokenExpires": 1440 |
||||
} |
||||
``` |
||||
|
||||
### 5.3 文件上传配置 |
||||
定义了多种文件类型的上传规则: |
||||
|
||||
``` |
||||
"UploadConfigConfiguration": { |
||||
"Avatar": { |
||||
"UploadPath": "../upload/admin/avatar", |
||||
"RequestPath": "/upload/admin/avatar", |
||||
"MaxSize": 1048576 |
||||
}, |
||||
"Image": { |
||||
"UploadPath": "../upload/admin/image", |
||||
"RequestPath": "/upload/admin/image", |
||||
"MaxSize": 10485760 |
||||
}, |
||||
"MaterialManager": { |
||||
"UploadPath": "../upload/admin/materials", |
||||
"RequestPath": "/upload/admin/materials" |
||||
} |
||||
} |
||||
``` |
||||
|
||||
## 6. 服务启动流程 |
||||
1. 入口点 : Program.cs 调用 HostApp.Run() 方法启动服务 |
||||
2. 配置加载 :通过 ConfigHelper 加载配置文件 |
||||
3. 依赖注入 :使用 Autofac 注册服务组件 |
||||
4. 数据库初始化 :应用数据库迁移和种子数据 |
||||
5. 中间件配置 :配置认证授权、CORS、路由等中间件 |
||||
6. 服务运行 :启动 Web 服务器和 SignalR 服务 |
||||
## 7. 关键特性 |
||||
### 7.1 动态 API |
||||
使用自定义的 DynamicApi 属性自动生成 API 接口,简化开发流程。 |
||||
|
||||
### 7.2 实时通信 |
||||
通过 SignalR 实现监管人员和系统之间的实时消息推送和通知。 |
||||
|
||||
### 7.3 审计日志 |
||||
系统内置审计日志功能,记录用户操作和系统事件。 |
||||
|
||||
### 7.4 定时任务 |
||||
使用 Quartz 框架实现系统定时任务,如数据同步、状态更新等。 |
||||
|
||||
### 7.5 多数据库支持 |
||||
通过 EF Core 支持多种数据库,当前使用 MySQL。 |
||||
|
||||
## 8. 部署配置 |
||||
系统支持 Docker 容器化部署,提供了 Dockerfile 用于构建镜像。默认监听端口为 8006。 |
||||
|
||||
## 9. 安全措施 |
||||
- JWT/IdentityServer4 身份认证 |
||||
- 基于角色的访问控制 |
||||
- 输入验证和防注入 |
||||
- CORS 跨域配置 |
||||
- 请求限流(使用 AspNetCoreRateLimit) |
||||
@ -0,0 +1,46 @@
|
||||
using ATS.NonCustodial.Domain.Shared.AggRootEntities; |
||||
using ATS.NonCustodial.Domain.Shared.Constants; |
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using ATS.NonCustodial.Shared.Common.Enums; |
||||
using ATS.NonCustodial.Shared.Common.Enums.IM; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using System.ComponentModel.DataAnnotations; |
||||
using System.ComponentModel.DataAnnotations.Schema; |
||||
using System.Numerics; |
||||
|
||||
namespace ATS.NonCustodial.Domain.Entities.Admins |
||||
{ |
||||
[Table("app_sms")] |
||||
public class AppSMS: EntityFull |
||||
{ |
||||
public AppSMS() |
||||
{ } |
||||
|
||||
public AppSMS(long id) |
||||
{ |
||||
Id = id; |
||||
} |
||||
public string? receiver { get; set; } |
||||
|
||||
public string phone { get; set; } = string.Empty; |
||||
|
||||
public string content { get; set; } = string.Empty; |
||||
|
||||
public string? code { get; set; } |
||||
|
||||
public DateTime sendTime { get; set; } |
||||
|
||||
public DateTime expiresTime { get; set; } |
||||
|
||||
public bool isUsed { get; set; } = false; |
||||
|
||||
public DateTime? useTime { get; set; } |
||||
|
||||
public string ipAddress { get; set; } = string.Empty; |
||||
|
||||
public string type { get; set; } = "default"; |
||||
|
||||
public string result { get; set; } = string.Empty; |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,593 @@
|
||||
using ATS.NonCustodial.Application.Base; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.AppDictionaries; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.AppDictionaries.Output; |
||||
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.Domain.Entities.Admins; |
||||
using ATS.NonCustodial.Domain.Entities.Business.CaseManagements; |
||||
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 System.Web; |
||||
|
||||
namespace ATS.NonCustodial.Application.Impl.Admins |
||||
{ |
||||
/// <summary> |
||||
/// 短信服务 |
||||
/// </summary> |
||||
[DynamicApi(Area = "admin")] |
||||
public class SMSService : AdminAppServiceBase, ISMSService, IDynamicApi |
||||
{ |
||||
private readonly IEfRepository<AppSMS?, long> _appSMSRepository; |
||||
private readonly IEfRepository<AppUser, long> _appUserRepository; |
||||
protected readonly IEfRepository<AppCaseManagement, long> _appCaseManagementRepository; |
||||
protected readonly IEfRepository<AppCaseSupervisedPerson, long> _appSupervisedPersonRepository; |
||||
private readonly HttpClient _httpClient; |
||||
protected readonly IAppDictionaryService _appDictionaryService; |
||||
|
||||
|
||||
public SMSService(IEfRepository<AppCaseManagement, long> appCaseManagementRepository, |
||||
IEfRepository<AppCaseSupervisedPerson, long> appSupervisedPersonRepository, |
||||
IEfRepository<AppSMS?, long> appSMSRepository, |
||||
IAppDictionaryService appDictionaryService, |
||||
IEfRepository<AppUser, long> appUserRepository) |
||||
{ |
||||
_appSMSRepository = appSMSRepository; |
||||
_appUserRepository = appUserRepository; |
||||
_appCaseManagementRepository = appCaseManagementRepository; |
||||
_appSupervisedPersonRepository = appSupervisedPersonRepository; |
||||
_appDictionaryService = appDictionaryService; |
||||
|
||||
// 配置HttpClient,忽略SSL证书验证(仅用于测试环境) |
||||
var handler = new HttpClientHandler() |
||||
{ |
||||
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true |
||||
}; |
||||
|
||||
_httpClient = new HttpClient(handler); |
||||
_httpClient.Timeout = TimeSpan.FromSeconds(30); |
||||
|
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// 分页查询 |
||||
/// </summary> |
||||
/// <param name="input"></param> |
||||
/// <returns></returns> |
||||
[HttpPost] |
||||
public async Task<IResultOutput> 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<AppSMS, SmsGetpageInput, SmsListDto>(input, express); |
||||
|
||||
foreach (var item in rtn.Data) |
||||
{ |
||||
|
||||
item.Name = item.Receiver; |
||||
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.Split("|")[0].Equals("OK")) |
||||
{ |
||||
item.Message = item.Result; |
||||
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); |
||||
} |
||||
/// <summary> |
||||
/// 查询实时预警条件 |
||||
/// </summary> |
||||
/// <param name="pageInput"></param> |
||||
/// <param name="query"></param> |
||||
/// <returns></returns> |
||||
private async Task<IQueryable<AppSMS>> GetExpression(SmsGetpageInput pageInput, IQueryable<AppSMS?> 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; |
||||
} |
||||
/// <summary> |
||||
/// 被监管人登录发送验证码 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <param name="ipAddress"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
[HttpGet] |
||||
[AllowAnonymous] |
||||
public async Task<IResultOutput> SendCheckCodeSMS(string phone, string ipAddress = "", string type = "CheckCode") |
||||
{ |
||||
// 检查是否可以发送(一分钟内只能发送一次) |
||||
if (!await CanSendCodeAsync(phone)) |
||||
{ |
||||
return ResultOutput.NotOk("请求过于频繁,请稍后再试"); |
||||
} |
||||
var personList = await _appUserRepository.AsQueryable(false, true).Where(w => w.Phone == phone).ToListAsync(); |
||||
|
||||
|
||||
if (personList.Count == 0) return ResultOutput.NotOk("请检查手机号是否输入正确"); |
||||
|
||||
var datalist = await (from a in _appCaseManagementRepository.AsQueryable(false, true) |
||||
.Where(w => w.CaseProgress != CaseProgressEnum.Closed) |
||||
join b in _appSupervisedPersonRepository.AsQueryable(false, true) |
||||
.Where(w => personList.Select(s => s.Id).ToList().Contains(w.SupervisedPersonId)) |
||||
on a.Id equals b.CaseId |
||||
select new { b.SupervisedPersonId }).ToListAsync(); |
||||
if (datalist.Count == 0) return ResultOutput.NotOk("该手机号不存在运行中的案件"); |
||||
|
||||
// 生成随机验证码(6位数字) |
||||
var random = new Random(); |
||||
var code = random.Next(100000, 999999).ToString(); |
||||
var name = personList.Where(w => datalist.Select(s => s.SupervisedPersonId).Contains(w.Id))?.FirstOrDefault().UserName ?? ""; |
||||
var sendMessage = $"您的验证码为:{code},请于五分钟内填写,若非本人操作,请勿泄露。"; |
||||
|
||||
// 创建验证码记录 |
||||
var addSMS = new AppSMS |
||||
{ |
||||
phone = phone, |
||||
code = code, |
||||
sendTime = DateTime.Now, |
||||
expiresTime = DateTime.Now.AddMinutes(5), // 5分钟有效期 |
||||
ipAddress = ipAddress, |
||||
type = type, |
||||
receiver = name, |
||||
content = sendMessage |
||||
}; |
||||
|
||||
var sendResult = SendSmsAsync(sendMessage, phone); |
||||
// 发送短信 |
||||
// var sendResult = SendSMS(phone, new string[] { code, "5" }, "2524683"); |
||||
addSMS.result = sendResult.Result; |
||||
var sms = await _appSMSRepository.InsertAsync(addSMS); |
||||
|
||||
return ResultOutput.Ok(true); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 监管人创建新用户或更改手机号发送验证码 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <param name="ipAddress"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
[HttpGet] |
||||
[AllowAnonymous] |
||||
public async Task<IResultOutput> SendCheckCode(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 name = "新用户注册"; |
||||
var sendMessage = $"您的验证码为:{code},请于5分钟内填写,若非本人操作,请勿泄露。"; |
||||
|
||||
// 创建验证码记录 |
||||
var addSMS = new AppSMS |
||||
{ |
||||
phone = phone, |
||||
code = code, |
||||
sendTime = DateTime.Now, |
||||
expiresTime = DateTime.Now.AddMinutes(5), // 5分钟有效期 |
||||
ipAddress = ipAddress, |
||||
type = type, |
||||
receiver = name, |
||||
content = sendMessage |
||||
}; |
||||
|
||||
var sendResult = SendSmsAsync(sendMessage, phone); |
||||
// 发送短信 |
||||
// var sendResult = SendSMS(phone, new string[] { code, "5" }, "2524683"); |
||||
addSMS.result = sendResult.Result; |
||||
var sms = await _appSMSRepository.InsertAsync(addSMS); |
||||
|
||||
return ResultOutput.Ok(true); |
||||
} |
||||
/// <summary> |
||||
/// 用于触发给指定人员发送短信 |
||||
/// </summary> |
||||
/// <param name="alert">短信通知类型</param> |
||||
/// <param name="supervisor">监管人姓名</param> |
||||
/// <param name="phone">需要通知的电话</param> |
||||
/// <param name="dateTime">发送的日期</param> |
||||
/// <param name="msg">触发的消息内容(小于等于6个字)</param> |
||||
/// <param name="ipAddress"></param> |
||||
/// <param name="supervisedPerson">被监管人姓名</param> |
||||
/// <returns></returns> |
||||
public async Task<IResultOutput> 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.Empty; |
||||
var date = dateTime.HasValue ? dateTime : DateTime.Now; |
||||
|
||||
if (alert == MessageAlertTypeEnum.Alert) |
||||
{ |
||||
//[预警处理提醒] {1}您好,您于{2}年{3}月{4}日触发的{5}预警需及时处理,请尽快核查并修正相关事项。 |
||||
sendMessage = $"[预警处理提醒] {supervisedPerson}您好,您于{date}触发的{msg}预警需及时处理,请尽快核查并遵守规定。"; |
||||
addSMS.type = "Alert"; |
||||
addSMS.receiver = supervisedPerson; |
||||
} |
||||
else if (alert == MessageAlertTypeEnum.Approved) |
||||
{ |
||||
//[审批完成通知] {1}您好,您于{2}年{3}月{4}日提交的{5}申请已完成审批,请及时登录系统查看处理结果。 |
||||
sendMessage = $"[审批完成通知] {supervisedPerson}您好,您于{date}提交的{msg}申请已完成审批,请及时登录系统查看处理结果。"; |
||||
addSMS.type = "Approved"; |
||||
addSMS.receiver = supervisedPerson; |
||||
|
||||
} |
||||
else if (alert == MessageAlertTypeEnum.ReviewNotification) |
||||
{ |
||||
//[待审批提醒] {1}您好,{2}于{3}年{4}月{5}日提交的{6}申请待您审批,请及时处理。 |
||||
sendMessage = $"[待审批提醒] {supervisor}您好,{supervisedPerson}于{date}提交的{msg}申请待您审批,请及时处理。"; |
||||
addSMS.type = "ReviewNotification"; |
||||
addSMS.receiver = supervisor; |
||||
|
||||
} |
||||
else |
||||
{ |
||||
//[监管预警通知] {1}您好,被监管人{2}于{3}年{4}月{5}日已触发{6}预警,请尽快核查处理。 |
||||
sendMessage = $"[监管预警通知] {supervisor}您好,被监管人{supervisedPerson}于{date}已触发{msg}预警,请尽快核查处理。"; |
||||
addSMS.type = "RegulatoryAlert"; |
||||
addSMS.receiver = supervisor; |
||||
} |
||||
// 发送短信 |
||||
var sendResult = SendSmsAsync(sendMessage, phone); |
||||
addSMS.result = sendResult.Result; |
||||
addSMS.content = sendMessage; |
||||
|
||||
//发送记录入库 |
||||
var sms = await _appSMSRepository.InsertAsync(addSMS); |
||||
|
||||
return ResultOutput.Ok(true); |
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// 校验验证码 |
||||
/// </summary> |
||||
/// <param name="phoneNumber"></param> |
||||
/// <param name="code"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
public async Task<bool> 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; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 发送前校验 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <returns></returns> |
||||
public async Task<bool> 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 |
||||
|
||||
|
||||
|
||||
/// <summary> |
||||
/// 发送短信接口 |
||||
/// </summary> |
||||
/// <param name="content">短信内容</param> |
||||
/// <param name="phone">电话号码</param> |
||||
/// <returns>接口返回消息</returns> |
||||
public async Task<string> SendSmsAsync(string content, string phone) |
||||
{ |
||||
try |
||||
{ |
||||
|
||||
// var smsConfig = LazyGetRequiredService<SmsConfiguration>(); |
||||
var signName = await GetDictionariesOutput("sms_config", "SignName"); |
||||
var feeType = await GetDictionariesOutput("sms_config", "FeeType"); |
||||
var baseUrl = await GetDictionariesOutput("sms_config", "BaseUrl"); |
||||
var pwd = await GetDictionariesOutput("sms_config", "Pwd"); |
||||
var loginName = await GetDictionariesOutput("sms_config", "LoginName"); |
||||
|
||||
var parameters = new SmsParameters() |
||||
{ |
||||
Pwd = pwd.Value, |
||||
Content = content, |
||||
FeeType = feeType.Value, |
||||
LoginName = loginName.Value, |
||||
SignName = signName.Value, |
||||
Mobile = phone |
||||
}; |
||||
|
||||
// 构建查询字符串 |
||||
var queryString = BuildQueryString(parameters); |
||||
var requestUrl = $"{baseUrl.Value}?{queryString}"; |
||||
|
||||
// 发送HTTP GET请求 |
||||
var response = await _httpClient.GetAsync(requestUrl); |
||||
|
||||
// 确保响应成功 |
||||
response.EnsureSuccessStatusCode(); |
||||
|
||||
// 读取响应内容 |
||||
return await response.Content.ReadAsStringAsync(); |
||||
} |
||||
catch (HttpRequestException ex) |
||||
{ |
||||
throw new Exception($"HTTP请求失败: {ex.Message}", ex); |
||||
} |
||||
catch (TaskCanceledException ex) |
||||
{ |
||||
throw new Exception($"请求超时: {ex.Message}", ex); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
throw new Exception($"发送短信失败: {ex.Message}", ex); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 构建查询字符串参数 |
||||
/// </summary> |
||||
private string BuildQueryString(SmsParameters parameters) |
||||
{ |
||||
var query = HttpUtility.ParseQueryString(string.Empty); |
||||
|
||||
query["LoginName"] = parameters.LoginName ?? ""; |
||||
query["Pwd"] = parameters.Pwd ?? ""; |
||||
query["FeeType"] = parameters.FeeType ?? ""; |
||||
query["Mobile"] = parameters.Mobile ?? ""; |
||||
query["Content"] = parameters.Content ?? ""; |
||||
query["SignName"] = parameters.SignName ?? ""; |
||||
query["TimingDate"] = parameters.TimingDate ?? ""; |
||||
query["ExtCode"] = parameters.ExtCode ?? ""; |
||||
|
||||
return query.ToString(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 带重试机制的发送方法 |
||||
/// </summary> |
||||
public async Task<string> SendSmsWithRetryAsync(string phone, string content, int maxRetries = 3) |
||||
{ |
||||
for (int i = 0; i < maxRetries; i++) |
||||
{ |
||||
try |
||||
{ |
||||
return await SendSmsAsync(content, phone); |
||||
} |
||||
catch (Exception ex) when (i < maxRetries - 1) |
||||
{ |
||||
Console.WriteLine($"第{i + 1}次尝试失败: {ex.Message}"); |
||||
await Task.Delay(1000 * (i + 1)); // 递增延迟 |
||||
} |
||||
} |
||||
|
||||
throw new Exception($"发送短信失败,已重试{maxRetries}次"); |
||||
} |
||||
/// <summary> |
||||
/// 根据字典类型Code和字典Code获取字典数据 |
||||
/// </summary> |
||||
/// <param name="dicTypeCode">字典类型Code</param> |
||||
/// <param name="dicCode">字典Code</param> |
||||
/// <returns></returns> |
||||
private async Task<DictionaryGetOutput> GetDictionariesOutput(string dicTypeCode, string dicCode) |
||||
{ |
||||
var dataDict = await _appDictionaryService.GetListNoApiAsync(null); |
||||
|
||||
//被监管人职位字典 |
||||
var dicData = dataDict |
||||
.FirstOrDefault(w => w.Code == dicTypeCode)?.Dictionaries! |
||||
.FirstOrDefault(w => w.Code == dicCode); |
||||
|
||||
//返回数据 |
||||
return dicData; |
||||
} |
||||
/// <summary> |
||||
/// 发送短信 |
||||
///【审批完成通知】 |
||||
//{0}您好,您于{1}提交的{2}申请已完成审批,请及时登录系统查看处理结果。 |
||||
//【预警处理提醒】 |
||||
//{0}您好,您于{1}触发的{2}预警需及时处理,请尽快核查并修正相关事项。 |
||||
//【监管预警通知】 |
||||
//{0}您好,被监管人{1}已触发{2}预警,请尽快核查处理。 |
||||
//【待审批提醒】 |
||||
//{0}您好,{1}于{2}提交的{3}申请待您审批,请及时处理。 |
||||
/// </summary> |
||||
/// <param name="phone">手机号</param> |
||||
/// <param name="messages">消息列表</param> |
||||
/// <param name="templateId">模版编号</param> |
||||
/// <returns></returns> |
||||
//private string SendSMS(string phone, string[] messages, string templateId) |
||||
//{ |
||||
// try |
||||
// { |
||||
// var smsConfig = LazyGetRequiredService<SmsConfiguration>(); |
||||
// // 密钥信息从环境变量读取,需要提前在环境变量中设置 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 |
||||
} |
||||
/// <summary> |
||||
/// 短信接口参数类 |
||||
/// </summary> |
||||
public class SmsParameters |
||||
{ |
||||
public string LoginName { get; set; } |
||||
public string Pwd { get; set; } |
||||
public string FeeType { get; set; } |
||||
public string Mobile { get; set; } |
||||
public string Content { get; set; } |
||||
public string SignName { get; set; } |
||||
public string TimingDate { get; set; } |
||||
public string ExtCode { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,53 @@
|
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS.Input; |
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using ATS.NonCustodial.Shared.Common.UnifiedResults; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS |
||||
{ |
||||
public interface ISMSService |
||||
{ |
||||
|
||||
Task<IResultOutput> GetPageAsync(SmsGetpageInput input); |
||||
/// <summary> |
||||
/// 发送验证码 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <returns></returns> |
||||
Task<IResultOutput> SendCheckCodeSMS(string phone, string ipAddress = "", string type = "CheckCode"); |
||||
/// <summary> |
||||
/// 监管人创建新用户或更改手机号发送验证码 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <param name="ipAddress"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
Task<IResultOutput> SendCheckCode(string phone, string ipAddress = "", string type = "CheckCode"); |
||||
/// <summary> |
||||
/// 校验验证码 |
||||
/// </summary> |
||||
/// <param name="phoneNumber"></param> |
||||
/// <param name="code"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
Task<bool> CheckCodeAsync(string phoneNumber, string code, string type = "default"); |
||||
/// <summary> |
||||
/// 用于触发给指定人员发送短信 |
||||
/// </summary> |
||||
/// <param name="alert">短信通知类型</param> |
||||
/// <param name="supervisor">监管人姓名</param> |
||||
/// <param name="phone">需要通知的电话</param> |
||||
/// <param name="dateTime">发送的日期</param> |
||||
/// <param name="msg">触发的消息内容(小于等于6个字)</param> |
||||
/// <param name="ipAddress"></param> |
||||
/// <param name="supervisedPerson">被监管人姓名</param> |
||||
/// <returns></returns> |
||||
Task<IResultOutput> SendMessageSMS(MessageAlertTypeEnum alert, string supervisor, string phone, DateTime? dateTime, string msg = "", string ipAddress = "", string supervisedPerson = ""); |
||||
|
||||
/// <summary> |
||||
/// 发送前校验 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <returns></returns> |
||||
Task<bool> CanSendCodeAsync(string phone); |
||||
} |
||||
} |
||||
@ -0,0 +1,33 @@
|
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using ATS.NonCustodial.Shared.Common.Dtos; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS.Input |
||||
{ |
||||
/// <summary> |
||||
/// 短信查询入参 |
||||
/// </summary> |
||||
/// Author:ZZJ |
||||
/// CreatedTimed:2025-10-15 10点42分 |
||||
public class SmsGetpageInput : PageRequestBaseInput |
||||
{ |
||||
/// <summary> |
||||
/// 电话号码 |
||||
/// </summary> |
||||
public string? Phone { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 姓名 |
||||
/// </summary> |
||||
public string? Name { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 开始时间 |
||||
/// </summary> |
||||
public DateTime? SendTimeFrom { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 结束时间 |
||||
/// </summary> |
||||
public DateTime? SendTimeTo { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,55 @@
|
||||
using ATS.NonCustodial.Domain.Shared.AggRootEntities; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS.Output |
||||
{ |
||||
public class SmsListDto : EntityFull |
||||
{ |
||||
/// <summary> |
||||
/// 姓名 |
||||
/// </summary> |
||||
public string? Name { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 编码 |
||||
/// </summary> |
||||
public long? Id { get; set; } |
||||
/// <summary> |
||||
/// 电话 |
||||
/// </summary> |
||||
public string? Phone { get; set; } |
||||
/// <summary> |
||||
/// 验证码 |
||||
/// </summary> |
||||
public string? Code { get; set; } |
||||
/// <summary> |
||||
/// 发送时间 |
||||
/// </summary> |
||||
public DateTime? SendTime { get; set; } |
||||
/// <summary> |
||||
/// 通知类型 |
||||
/// </summary> |
||||
public string? Type { get; set; } |
||||
/// <summary> |
||||
/// 通知类型描述 |
||||
/// </summary> |
||||
public string? TypeDes { get; set; } |
||||
/// <summary> |
||||
/// 发送结果 |
||||
/// </summary> |
||||
public string? Result { get; set; } |
||||
/// <summary> |
||||
/// 详细描述 |
||||
/// </summary> |
||||
public string? Message { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 接收人姓名 |
||||
/// </summary> |
||||
public string? Receiver { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,37 @@
|
||||
using ATS.NonCustodial.Shared.Common.Dtos; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Business.ViolationStatistics.Input |
||||
{ |
||||
public class NotClockedInput: PageRequestBaseInput |
||||
{ |
||||
/// <summary> |
||||
/// 案件Id |
||||
/// </summary> |
||||
public long? CaseId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 结束时间 |
||||
/// </summary> |
||||
public DateTime? EndCreatedTime { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 开始时间 |
||||
/// </summary> |
||||
public DateTime? StartCreatedTime { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件进度 |
||||
/// </summary> |
||||
public int? CaseProgress { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人姓名 |
||||
/// </summary> |
||||
public string? SupervisedPersonName { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,68 @@
|
||||
using ATS.NonCustodial.Domain.Shared.AggRootEntities; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Business.ViolationStatistics.Output |
||||
{ |
||||
/// <summary> |
||||
/// 未打卡统计返回值 |
||||
/// </summary> |
||||
public class NotClockExportDto |
||||
{ |
||||
/// <summary> |
||||
/// 案件Id |
||||
/// </summary> |
||||
public long CaseId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件名称 |
||||
/// </summary> |
||||
[DisplayName("案件名称")] |
||||
public string? CaseName { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人Id |
||||
/// </summary> |
||||
public long SupervisedPersonId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人员 |
||||
/// </summary> |
||||
[DisplayName("被监管人")] |
||||
public string? SupervisedPersonName { get; set; } |
||||
/// <summary> |
||||
/// 部门受案号 |
||||
/// </summary> |
||||
[DisplayName("部门受案号")] |
||||
public string? Bmsah { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 监督单位 |
||||
/// </summary> |
||||
[DisplayName("监督单位")] |
||||
public string? SupervisionUnit { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 案件类型 |
||||
/// </summary> |
||||
[DisplayName("案件类型")] |
||||
public string? CaseTypeName { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 未打卡次数 |
||||
/// </summary> |
||||
[DisplayName("未打卡次数")] |
||||
public int NotClockedCount { get; set; } |
||||
/// <summary> |
||||
/// 案件创建日期 |
||||
/// </summary> |
||||
[DisplayName("案件创建日期")] |
||||
public DateTime? CreatedTime { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,60 @@
|
||||
using ATS.NonCustodial.Domain.Shared.AggRootEntities; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Business.ViolationStatistics.Output |
||||
{ |
||||
/// <summary> |
||||
/// 未打卡统计返回值 |
||||
/// </summary> |
||||
public class NotClockListDto |
||||
{ |
||||
/// <summary> |
||||
/// 案件Id |
||||
/// </summary> |
||||
public long CaseId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件名称 |
||||
/// </summary> |
||||
public string? CaseName { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人Id |
||||
/// </summary> |
||||
public long SupervisedPersonId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人员 |
||||
/// </summary> |
||||
public string? SupervisedPersonName { get; set; } |
||||
/// <summary> |
||||
/// 部门受案号 |
||||
/// </summary> |
||||
public string? Bmsah { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 监督单位 |
||||
/// </summary> |
||||
public string? SupervisionUnit { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 案件类型 |
||||
/// </summary> |
||||
public string? CaseTypeName { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 未打卡次数 |
||||
/// </summary> |
||||
public int NotClockedCount { get; set; } |
||||
/// <summary> |
||||
/// 案件创建日期 |
||||
/// </summary> |
||||
public DateTime? CreatedTime { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,64 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Business.ViolationStatistics.Output |
||||
{ |
||||
public class ViolationExportDto |
||||
{ |
||||
/// <summary> |
||||
/// 案件Id |
||||
/// </summary> |
||||
public long CaseId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件名称 |
||||
/// </summary> |
||||
[DisplayName("案件名称")] |
||||
public string? CaseName { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人Id |
||||
/// </summary> |
||||
public long SupervisedPersonId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人员 |
||||
/// </summary> |
||||
[DisplayName("被监管人员")] |
||||
public string? SupervisedPersonName { get; set; } |
||||
/// <summary> |
||||
/// 部门受案号 |
||||
/// </summary> |
||||
[DisplayName("部门受案号")] |
||||
public string? Bmsah { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 监督单位 |
||||
/// </summary> |
||||
[DisplayName("监督单位")] |
||||
public string? SupervisionUnit { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 案件类型 |
||||
/// </summary> |
||||
[DisplayName("案件类型")] |
||||
public string? CaseTypeName { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 违规越界次数 |
||||
/// </summary> |
||||
[DisplayName("违规越界次数")] |
||||
public int ViolationCount { get; set; } |
||||
/// <summary> |
||||
/// 案件创建日期 |
||||
/// </summary> |
||||
[DisplayName("案件创建日期")] |
||||
public DateTime? CreatedTime { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Business.ViolationStatistics.Output |
||||
{ |
||||
public class ViolationListDto |
||||
{ |
||||
/// <summary> |
||||
/// 案件Id |
||||
/// </summary> |
||||
public long CaseId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件名称 |
||||
/// </summary> |
||||
public string? CaseName { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人Id |
||||
/// </summary> |
||||
public long SupervisedPersonId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人员 |
||||
/// </summary> |
||||
public string? SupervisedPersonName { get; set; } |
||||
/// <summary> |
||||
/// 部门受案号 |
||||
/// </summary> |
||||
public string? Bmsah { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 监督单位 |
||||
/// </summary> |
||||
public string? SupervisionUnit { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 案件类型 |
||||
/// </summary> |
||||
public string? CaseTypeName { get; set; } |
||||
|
||||
|
||||
/// <summary> |
||||
/// 违规越界次数 |
||||
/// </summary> |
||||
public int ViolationCount { get; set; } |
||||
/// <summary> |
||||
/// 案件创建日期 |
||||
/// </summary> |
||||
public DateTime? CreatedTime { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,64 @@
|
||||
using ATS.NonCustodial.Domain.Shared.AggRootEntities; |
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using System.ComponentModel; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Business.ViolationStatistics.Output |
||||
{ |
||||
/// <summary> |
||||
/// 违规统计列表Dto |
||||
/// </summary> |
||||
/// Author:mxg |
||||
/// CreatedTimed:2022-06-06 05:19 PM |
||||
public class ViolationStatisticsExportDto |
||||
{ |
||||
/// <summary> |
||||
/// 案件Id |
||||
/// </summary> |
||||
public long CaseId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件名称 |
||||
/// </summary> |
||||
[DisplayName("案件名称")] |
||||
public string? CaseName { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人Id |
||||
/// </summary> |
||||
public long SupervisedPersonId { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 被监管人员 |
||||
/// </summary> |
||||
[DisplayName("被监管人员")] |
||||
public string? SupervisedPersonName { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 身份证号 |
||||
/// </summary> |
||||
[DisplayName("身份证号")] |
||||
public string? IdCard { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 违规次数 |
||||
/// </summary> |
||||
[DisplayName("违规次数")] |
||||
public int Violations { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 违规时间 |
||||
/// </summary> |
||||
public DateTime? Wgtime { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 违规类型 |
||||
/// </summary> |
||||
public string Wglx { get; set; } |
||||
|
||||
/// <summary> |
||||
/// 案件进度 |
||||
/// </summary> |
||||
[DisplayName("案件进度")] |
||||
public string? CaseProgress { get; set; } |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
using System.ComponentModel; |
||||
|
||||
namespace ATS.NonCustodial.Domain.Shared.Enums |
||||
{ |
||||
/// <summary> |
||||
/// 短信通知类型 |
||||
/// </summary> |
||||
public enum MessageAlertTypeEnum |
||||
{ |
||||
/// <summary> |
||||
/// 审批完成通知 |
||||
/// </summary> |
||||
[Description("审批完成")] |
||||
Approved = 0, |
||||
|
||||
/// <summary> |
||||
/// 监管预警通知(用于通知监管人) |
||||
/// </summary> |
||||
[Description("监管预警")] |
||||
RegulatoryAlert = 1, |
||||
|
||||
/// <summary> |
||||
/// 审批提醒通知 |
||||
/// </summary> |
||||
[Description("审批提醒")] |
||||
ReviewNotification = 2, |
||||
/// <summary> |
||||
/// 预警处理通知(用于通知被监管人) |
||||
/// </summary> |
||||
[Description("预警处理")] |
||||
Alert = 3 |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ATS.NonCustodial.Shared.Configurations.Options |
||||
{ |
||||
public class SmsConfiguration |
||||
{ |
||||
public string LoginName { get; set; } |
||||
|
||||
public string Pwd { get; set; } |
||||
|
||||
public string BaseUrl { get; set; } |
||||
|
||||
public string FeeType { get; set; } |
||||
|
||||
public string SignName { get; set; } |
||||
} |
||||
} |
||||
Loading…
Reference in new issue