From 1d7acde24e06a5f11a9fe2c9ce600dbd54788ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Mon, 30 Mar 2026 11:23:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E4=BD=8D=E8=AE=A4=E8=AF=81=E8=A1=A8?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/MerchantCertificationDtos.cs | 162 +++++++++++++ .../Merchant/Dtos/SubmitCertificationInput.cs | 46 ---- .../Merchant/MerchantCertificationService.cs | 219 ++++++++++++++++++ .../Merchant/MerchantService.cs | 118 +--------- YD_Event.Application/YD_Event.Application.xml | 215 +++++++++++++---- .../Entities/MerchantCertification.cs | 86 +++++++ YD_Event.Core/YD_Event.Core.xml | 75 ++++++ 7 files changed, 713 insertions(+), 208 deletions(-) create mode 100644 YD_Event.Application/Merchant/Dtos/MerchantCertificationDtos.cs delete mode 100644 YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs create mode 100644 YD_Event.Application/Merchant/MerchantCertificationService.cs create mode 100644 YD_Event.Core/Entities/MerchantCertification.cs diff --git a/YD_Event.Application/Merchant/Dtos/MerchantCertificationDtos.cs b/YD_Event.Application/Merchant/Dtos/MerchantCertificationDtos.cs new file mode 100644 index 0000000..0136c2c --- /dev/null +++ b/YD_Event.Application/Merchant/Dtos/MerchantCertificationDtos.cs @@ -0,0 +1,162 @@ +using System.ComponentModel.DataAnnotations; +using YD_Event.Core.Enum; + +namespace YD_Event.Application.Merchant.Dtos; + +/// +/// 单位认证输出 +/// +public class MerchantCertificationOutput +{ + /// + /// 主键ID + /// + public long Id { get; set; } + + /// + /// 用户ID + /// + public long UserId { get; set; } + + /// + /// 单位名称 + /// + public string MerchantName { get; set; } + + /// + /// 统一社会信用代码 + /// + public string CreditCode { get; set; } + + /// + /// 营业执照图片URL + /// + public string BusinessLicenseUrl { get; set; } + + /// + /// 联系电话 + /// + public string ContactPhone { get; set; } + + /// + /// 地址 + /// + public string Address { get; set; } + + /// + /// 审核状态 + /// + public AuditStatus AuditStatus { get; set; } + + /// + /// 审核备注 + /// + public string? AuditRemark { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdatedTime { get; set; } +} + +/// +/// 提交单位认证输入 +/// +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; } +} + +/// +/// 审核单位认证输入 +/// +public class AuditCertificationInput +{ + /// + /// 认证ID列表 + /// + [Required(ErrorMessage = "认证ID不能为空")] + public List Ids { get; set; } + + /// + /// 审核状态 + /// + [Required(ErrorMessage = "审核状态不能为空")] + public AuditStatus Status { get; set; } + + /// + /// 审核备注 + /// + public string? Remark { get; set; } +} + +/// +/// 单位认证查询输入 +/// +public class MerchantCertificationQueryInput : Pagination +{ + /// + /// 单位名称 + /// + public string? MerchantName { get; set; } + + /// + /// 联系电话 + /// + public string? ContactPhone { get; set; } + + /// + /// 审核状态 + /// + public AuditStatus? AuditStatus { get; set; } + + /// + /// 开始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } +} diff --git a/YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs b/YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs deleted file mode 100644 index e3d20a8..0000000 --- a/YD_Event.Application/Merchant/Dtos/SubmitCertificationInput.cs +++ /dev/null @@ -1,46 +0,0 @@ -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/MerchantCertificationService.cs b/YD_Event.Application/Merchant/MerchantCertificationService.cs new file mode 100644 index 0000000..c1e086f --- /dev/null +++ b/YD_Event.Application/Merchant/MerchantCertificationService.cs @@ -0,0 +1,219 @@ +using Microsoft.Extensions.Caching.Memory; +using YD_Event.Application.Auth; +using YD_Event.Application.Merchant.Dtos; +using YD_Event.Core.Entities; +using YD_Event.Core.Enum; +using YD_Event.Core.Infrastructure.Aliyun.Sms; + +namespace YD_Event.Application.Merchant; + +/// +/// 单位认证管理 +/// +public class MerchantCertificationService : BaseService, ITransient +{ + private readonly ISqlSugarRepository _repository; + private readonly ISqlSugarRepository _merchantRepository; + private readonly AuthManager _authManager; + private readonly IIdGenerator _idGenerator; + private readonly IMemoryCache _memoryCache; + private readonly AliyunSmsService _smsService; + + public MerchantCertificationService( + ISqlSugarRepository repository, + ISqlSugarRepository merchantRepository, + AuthManager authManager, + IIdGenerator idGenerator, + IMemoryCache memoryCache, + AliyunSmsService smsService) : base(repository) + { + _repository = repository; + _merchantRepository = merchantRepository; + _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("手机号格式不正确"); + + var code = new Random().Next(100000, 999999).ToString(); + _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 certification = await _repository.GetFirstAsync(c => c.UserId == userId && !c.DeleteMark); + + if (certification == null) + { + certification = new MerchantCertification + { + Id = _idGenerator.NextId(), + UserId = userId, + MerchantName = input.MerchantName, + CreditCode = input.CreditCode, + BusinessLicenseUrl = input.BusinessLicenseUrl, + Address = input.Address, + ContactPhone = input.ContactPhone, + AuditStatus = AuditStatus.PendingAudit, + Status = AvailabilityStatus.Enable, + DeleteMark = false, + CreatedUserId = userId, + CreatedTime = DateTime.Now + }; + await _repository.InsertAsync(certification); + } + else + { + certification.MerchantName = input.MerchantName; + certification.CreditCode = input.CreditCode; + certification.BusinessLicenseUrl = input.BusinessLicenseUrl; + certification.Address = input.Address; + certification.ContactPhone = input.ContactPhone; + certification.AuditStatus = AuditStatus.PendingAudit; + certification.UpdatedUserId = userId; + certification.UpdatedTime = DateTime.Now; + await _repository.UpdateAsync(certification); + } + + _memoryCache.Remove($"verification_code_{input.ContactPhone}"); + } + + /// + /// 获取我的认证信息 + /// + [DisplayName("获取我的认证信息")] + [HttpGet("myCertification")] + public async Task GetMyCertification() + { + var userId = _authManager.UserId; + var certification = await _repository.GetFirstAsync(c => c.UserId == userId && !c.DeleteMark); + return certification?.Adapt(); + } + + /// + /// 单位认证分页查询 + /// + [DisplayName("单位认证分页查询")] + [HttpGet("page")] + public async Task> Page([FromQuery] MerchantCertificationQueryInput input) + { + var pageResult = await _repository.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.MerchantName), x => x.MerchantName.Contains(input.MerchantName)) + .WhereIF(!string.IsNullOrWhiteSpace(input.ContactPhone), x => x.ContactPhone.Contains(input.ContactPhone)) + .WhereIF(input.AuditStatus.HasValue, x => x.AuditStatus == input.AuditStatus) + .WhereIF(input.StartTime.HasValue, x => x.CreatedTime >= input.StartTime) + .WhereIF(input.EndTime.HasValue, x => x.CreatedTime <= input.EndTime) + .OrderByDescending(x => x.CreatedTime) + .Select(x => new MerchantCertificationOutput + { + Id = x.Id, + UserId = x.UserId, + MerchantName = x.MerchantName, + CreditCode = x.CreditCode, + BusinessLicenseUrl = x.BusinessLicenseUrl, + ContactPhone = x.ContactPhone, + Address = x.Address, + AuditStatus = x.AuditStatus, + AuditRemark = x.AuditRemark, + CreatedTime = x.CreatedTime, + UpdatedTime = x.UpdatedTime + }) + .ToPagedListAsync(input); + + return pageResult; + } + + /// + /// 获取单位认证详情 + /// + [DisplayName("获取单位认证详情")] + [HttpGet("detail")] + public async Task Detail([FromQuery] long id) + { + var certification = await _repository.GetByIdAsync(id); + return certification?.Adapt(); + } + + /// + /// 审核单位认证 + /// + [DisplayName("审核单位认证")] + [HttpPost("audit")] + [UnitOfWork] + public async Task Audit([FromBody] AuditCertificationInput input) + { + if (input.Ids == null || !input.Ids.Any()) return; + + var certifications = await _repository.GetListAsync(c => input.Ids.Contains(c.Id) && !c.DeleteMark); + var userId = _authManager.UserId; + + foreach (var certification in certifications) + { + certification.AuditStatus = input.Status; + certification.AuditRemark = input.Remark; + certification.UpdatedUserId = userId; + certification.UpdatedTime = DateTime.Now; + + if (input.Status == AuditStatus.Pass) + { + var merchant = await _merchantRepository.GetFirstAsync(m => m.CreatedUserId == certification.UserId && !m.DeleteMark); + if (merchant == null) + { + merchant = new YD_Event.Core.Entities.Merchant + { + Id = _idGenerator.NextId(), + MerchantName = certification.MerchantName, + CreditCode = certification.CreditCode, + BusinessLicenseUrl = certification.BusinessLicenseUrl, + Address = certification.Address, + ContactPhone = certification.ContactPhone, + BankName = "", + AccountNumber = "", + AuditStatus = AuditStatus.Pass, + Status = AvailabilityStatus.Enable, + DeleteMark = false, + CreatedUserId = certification.UserId, + CreatedTime = DateTime.Now + }; + await _merchantRepository.InsertAsync(merchant); + } + else + { + merchant.MerchantName = certification.MerchantName; + merchant.CreditCode = certification.CreditCode; + merchant.BusinessLicenseUrl = certification.BusinessLicenseUrl; + merchant.Address = certification.Address; + merchant.ContactPhone = certification.ContactPhone; + merchant.UpdatedUserId = userId; + merchant.UpdatedTime = DateTime.Now; + await _merchantRepository.UpdateAsync(merchant); + } + } + } + + await _repository.UpdateRangeAsync(certifications); + } +} diff --git a/YD_Event.Application/Merchant/MerchantService.cs b/YD_Event.Application/Merchant/MerchantService.cs index 353d59a..6c74e6f 100644 --- a/YD_Event.Application/Merchant/MerchantService.cs +++ b/YD_Event.Application/Merchant/MerchantService.cs @@ -1,7 +1,5 @@ -using Microsoft.Extensions.Caching.Memory; using YD_Event.Application.Auth; using YD_Event.Application.Merchant.Dtos; -using YD_Event.Core.Infrastructure.Aliyun.Sms; using YD_Event.Core.Entities; using YD_Event.Core.Enum; @@ -17,113 +15,18 @@ public class MerchantService : BaseService, ITr private readonly ISqlSugarRepository _weChatPayConfigRepository; private readonly AuthManager _authManager; private readonly IIdGenerator _idGenerator; - private readonly IMemoryCache _memoryCache; - private readonly AliyunSmsService _smsService; public MerchantService(ISqlSugarRepository repository, ISqlSugarRepository userCouponRepository, ISqlSugarRepository weChatPayConfigRepository, AuthManager authManager, - IIdGenerator idGenerator, - IMemoryCache memoryCache, - AliyunSmsService smsService) : base(repository) + IIdGenerator idGenerator) : base(repository) { _repository = repository; _userCouponRepository = userCouponRepository; _weChatPayConfigRepository = weChatPayConfigRepository; _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; } /// @@ -263,25 +166,6 @@ public class MerchantService : BaseService, ITr }; } - /// - /// 审核商户 - /// - [DisplayName("审核商户")] - [HttpPost("audit")] - [UnitOfWork] - public async Task Audit([FromBody] MerchantAuditInput input) - { - if (input.Ids == null || !input.Ids.Any()) return; - - await _repository.UpdateAsync(u => new YD_Event.Core.Entities.Merchant - { - AuditStatus = input.Status, - AuditRemark = input.Remark, - UpdatedTime = DateTime.Now, - UpdatedUserId = _authManager.UserId - }, u => input.Ids.Contains(u.Id)); - } - /// /// 发放优惠券 /// diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 9d32ddf..227ddbf 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -6063,6 +6063,151 @@ 微信支付配置 + + + 单位认证输出 + + + + + 主键ID + + + + + 用户ID + + + + + 单位名称 + + + + + 统一社会信用代码 + + + + + 营业执照图片URL + + + + + 联系电话 + + + + + 地址 + + + + + 审核状态 + + + + + 审核备注 + + + + + 创建时间 + + + + + 更新时间 + + + + + 提交单位认证输入 + + + + + 单位名称 + + + + + 统一社会信用代码 + + + + + 营业执照图片URL + + + + + 地址 + + + + + 联系方式 + + + + + 验证码 + + + + + 审核单位认证输入 + + + + + 认证ID列表 + + + + + 审核状态 + + + + + 审核备注 + + + + + 单位认证查询输入 + + + + + 单位名称 + + + + + 联系电话 + + + + + 审核状态 + + + + + 开始时间 + + + + + 结束时间 + + 商户输出DTO @@ -6238,41 +6383,6 @@ 备注 - - - 提交认证输入 - - - - - 单位名称 - - - - - 统一社会信用代码 - - - - - 营业执照图片URL - - - - - 地址 - - - - - 联系方式 - - - - - 验证码 - - 更新商户输入 @@ -6353,26 +6463,46 @@ 可用状态 - + - 商户管理 + 单位认证管理 - + 发送验证码 - + 提交单位认证 - + 获取我的认证信息 + + + 单位认证分页查询 + + + + + 获取单位认证详情 + + + + + 审核单位认证 + + + + + 商户管理 + + 商户分页查询 @@ -6398,11 +6528,6 @@ 获取商户详情 - - - 审核商户 - - 发放优惠券 diff --git a/YD_Event.Core/Entities/MerchantCertification.cs b/YD_Event.Core/Entities/MerchantCertification.cs new file mode 100644 index 0000000..af8d7e0 --- /dev/null +++ b/YD_Event.Core/Entities/MerchantCertification.cs @@ -0,0 +1,86 @@ +using YD_Event.Core.Enum; + +namespace YD_Event.Core.Entities; + +/// +/// 单位认证表 +/// +[SugarTable("MerchantCertification")] +public class MerchantCertification : Entity, ISoftDelete, ICreatedUserId, ICreatedTime, IUpdatedUserId, IUpdatedTime, IAvailability +{ + /// + /// 用户ID + /// + public long UserId { get; set; } + + /// + /// 单位名称 + /// + [SugarColumn(Length = 128)] + public string MerchantName { get; set; } + + /// + /// 统一社会信用代码 + /// + [SugarColumn(Length = 50)] + public string CreditCode { get; set; } + + /// + /// 营业执照图片URL + /// + [SugarColumn(Length = 256)] + public string BusinessLicenseUrl { get; set; } + + /// + /// 联系电话 + /// + [SugarColumn(Length = 16)] + public string ContactPhone { get; set; } + + /// + /// 地址 + /// + [SugarColumn(Length = 256)] + public string Address { get; set; } + + /// + /// 审核状态 + /// + public AuditStatus AuditStatus { get; set; } + + /// + /// 审核备注 + /// + [SugarColumn(Length = 512)] + public string? AuditRemark { get; set; } + + /// + /// 可用状态 + /// + public AvailabilityStatus Status { get; set; } + + /// + /// 标记删除 + /// + public bool DeleteMark { get; set; } + + /// + /// 创建人 + /// + public long CreatedUserId { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 更新人 + /// + public long? UpdatedUserId { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdatedTime { get; set; } +} diff --git a/YD_Event.Core/YD_Event.Core.xml b/YD_Event.Core/YD_Event.Core.xml index a595fa5..712da65 100644 --- a/YD_Event.Core/YD_Event.Core.xml +++ b/YD_Event.Core/YD_Event.Core.xml @@ -2455,6 +2455,81 @@ 更新时间 + + + 单位认证表 + + + + + 用户ID + + + + + 单位名称 + + + + + 统一社会信用代码 + + + + + 营业执照图片URL + + + + + 联系电话 + + + + + 地址 + + + + + 审核状态 + + + + + 审核备注 + + + + + 可用状态 + + + + + 标记删除 + + + + + 创建人 + + + + + 创建时间 + + + + + 更新人 + + + + + 更新时间 + + 订单表