diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs
index 58887ba5..d2e85949 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Pay/CreateOrderInput.cs
@@ -1,3 +1,4 @@
+using System.ComponentModel.DataAnnotations;
using Yi.Framework.AiHub.Domain.Shared.Enums;
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Pay;
@@ -10,5 +11,6 @@ public class CreateOrderInput
///
/// 商品类型
///
+ [Required]
public GoodsTypeEnum GoodsType { get; set; }
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Recharge/RechargeCreateInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Recharge/RechargeCreateInput.cs
index a8354fb7..96aa06ce 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Recharge/RechargeCreateInput.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Recharge/RechargeCreateInput.cs
@@ -25,9 +25,10 @@ public class RechargeCreateInput
public string Content { get; set; } = string.Empty;
///
- /// 到期时间(为空表示永久VIP)
+ /// VIP月数(为空或0表示永久VIP)
///
- public DateTime? ExpireDateTime { get; set; }
+ [Range(0, int.MaxValue, ErrorMessage = "月数必须大于等于0")]
+ public int? Months { get; set; }
///
/// 备注
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IRechargeService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IRechargeService.cs
index 6d821715..838d392f 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IRechargeService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IRechargeService.cs
@@ -1,4 +1,6 @@
-namespace Yi.Framework.AiHub.Application.Contracts.IServices;
+using Yi.Framework.AiHub.Application.Contracts.Dtos.Recharge;
+
+namespace Yi.Framework.AiHub.Application.Contracts.IServices;
public interface IRechargeService
{
@@ -6,4 +8,11 @@ public interface IRechargeService
/// 移除用户vip及角色
///
Task RemoveVipRoleByExpireAsync();
+
+ ///
+ /// 给用户充值VIP
+ ///
+ /// 充值输入参数
+ ///
+ Task RechargeVipAsync(RechargeCreateInput input);
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs
index 89711314..77e00f93 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/PayService.cs
@@ -14,6 +14,7 @@ using Yi.Framework.AiHub.Domain.Entities.Pay;
using Yi.Framework.SqlSugarCore.Abstractions;
using System.ComponentModel;
using System.Reflection;
+using Yi.Framework.AiHub.Application.Contracts.Dtos.Recharge;
namespace Yi.Framework.AiHub.Application.Services;
@@ -26,16 +27,19 @@ public class PayService : ApplicationService, IPayService
private readonly PayManager _payManager;
private readonly ILogger _logger;
private readonly ISqlSugarRepository _payOrderRepository;
+ private readonly IRechargeService _rechargeService;
public PayService(
AlipayManager alipayManager,
PayManager payManager,
- ILogger logger, ISqlSugarRepository payOrderRepository)
+ ILogger logger, ISqlSugarRepository payOrderRepository,
+ IRechargeService rechargeService)
{
_alipayManager = alipayManager;
_payManager = payManager;
_logger = logger;
_payOrderRepository = payOrderRepository;
+ _rechargeService = rechargeService;
}
///
@@ -89,7 +93,7 @@ public class PayService : ApplicationService, IPayService
// 3. 记录支付通知
- await _payManager.RecordPayNoticeAsync(notifyData,signStr);
+ await _payManager.RecordPayNoticeAsync(notifyData, signStr);
// 4. 更新订单状态
var outTradeNo = notifyData.GetValueOrDefault("out_trade_no", string.Empty);
@@ -99,9 +103,20 @@ public class PayService : ApplicationService, IPayService
if (!string.IsNullOrEmpty(outTradeNo) && !string.IsNullOrEmpty(tradeStatus))
{
var status = ParseTradeStatus(tradeStatus);
- await _payManager.UpdateOrderStatusAsync(outTradeNo, status, tradeNo);
+ var order = await _payManager.UpdateOrderStatusAsync(outTradeNo, status, tradeNo);
_logger.LogInformation("订单状态更新成功,订单号:{OutTradeNo},状态:{TradeStatus}", outTradeNo, tradeStatus);
+
+ //5.充值Vip
+ await _rechargeService.RechargeVipAsync(new RechargeCreateInput
+ {
+ UserId = order.UserId,
+ RechargeAmount = order.TotalAmount,
+ Content = order.GoodsName,
+ Months = order.GoodsType.GetValidMonths(),
+ Remark = "自助充值",
+ ContactInfo = null
+ });
}
else
{
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/RechargeService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/RechargeService.cs
index 0bc30196..082a9093 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/RechargeService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/RechargeService.cs
@@ -13,7 +13,7 @@ using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services
{
- public class RechargeService : ApplicationService,IRechargeService
+ public class RechargeService : ApplicationService, IRechargeService
{
private readonly ISqlSugarRepository _repository;
private readonly ICurrentUser _currentUser;
@@ -57,13 +57,33 @@ namespace Yi.Framework.AiHub.Application.Services
[HttpPost("recharge/vip")]
public async Task RechargeVipAsync(RechargeCreateInput input)
{
+ DateTime? expireDateTime = null;
+
+ // 如果传入了月数,计算过期时间
+ if (input.Months.HasValue && input.Months.Value > 0)
+ {
+ // 直接查询该用户最大的过期时间
+ var maxExpireTime = await _repository._DbQueryable
+ .Where(x => x.UserId == input.UserId && x.ExpireDateTime.HasValue)
+ .MaxAsync(x => x.ExpireDateTime);
+
+ // 如果最大过期时间大于现在时间,从最大过期时间开始计算
+ // 否则从当天开始计算
+ DateTime baseDateTime = maxExpireTime.HasValue && maxExpireTime.Value > DateTime.Now
+ ? maxExpireTime.Value
+ : DateTime.Now;
+ // 计算新的过期时间
+ expireDateTime = baseDateTime.AddMonths(input.Months.Value);
+ }
+ // 如果月数为空或0,表示永久VIP,ExpireDateTime保持为null
+
// 创建充值记录
var rechargeRecord = new AiRechargeAggregateRoot
{
UserId = input.UserId,
RechargeAmount = input.RechargeAmount,
Content = input.Content,
- ExpireDateTime = input.ExpireDateTime,
+ ExpireDateTime = expireDateTime,
Remark = input.Remark,
ContactInfo = input.ContactInfo
};
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs
index 6d674456..83b62e0d 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs
@@ -10,10 +10,12 @@ namespace Yi.Framework.AiHub.Domain.Shared.Enums;
public class PriceAttribute : Attribute
{
public decimal Price { get; }
+ public int ValidMonths { get; }
- public PriceAttribute(double price)
+ public PriceAttribute(double price, int validMonths)
{
Price = (decimal)price;
+ ValidMonths = validMonths;
}
}
@@ -36,23 +38,23 @@ public class DisplayNameAttribute : Attribute
///
public enum GoodsTypeEnum
{
- [Price(0.01)]
+ [Price(0.01, 1)]
[DisplayName("YiXinVip Test")]
YiXinVipTest = 0,
- [Price(29.9)]
+ [Price(29.9, 1)]
[DisplayName("YiXinVip 1 month")]
YiXinVip1 = 1,
- [Price(80.7)]
+ [Price(80.7, 3)]
[DisplayName("YiXinVip 3 month")]
YiXinVip3 = 3,
- [Price(143.9)]
+ [Price(143.9, 6)]
[DisplayName("YiXinVip 6 month")]
YiXinVip6 = 6,
- [Price(199.9)]
+ [Price(199.9, 10)]
[DisplayName("YiXinVip 10 month")]
YiXinVip10 = 10
}
@@ -93,4 +95,28 @@ public static class GoodsTypeEnumExtensions
var displayNameAttribute = fieldInfo?.GetCustomAttribute();
return displayNameAttribute?.DisplayName ?? goodsType.ToString();
}
+
+ ///
+ /// 获取商品有效月份
+ ///
+ /// 商品类型
+ /// 有效月份
+ public static int GetValidMonths(this GoodsTypeEnum goodsType)
+ {
+ var fieldInfo = goodsType.GetType().GetField(goodsType.ToString());
+ var priceAttribute = fieldInfo?.GetCustomAttribute();
+ return priceAttribute?.ValidMonths ?? 1;
+ }
+
+ ///
+ /// 获取商品月均价格
+ ///
+ /// 商品类型
+ /// 月均价格
+ public static decimal GetMonthlyPrice(this GoodsTypeEnum goodsType)
+ {
+ var totalPrice = goodsType.GetTotalAmount();
+ var validMonths = goodsType.GetValidMonths();
+ return validMonths > 0 ? totalPrice / validMonths : 0m;
+ }
}
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs
index f967fa15..5a36122c 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Alipay/AlipayManager.cs
@@ -1,6 +1,7 @@
using Alipay.EasySDK.Factory;
using Alipay.EasySDK.Kernel.Util;
using Alipay.EasySDK.Payment.Page.Models;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Services;
@@ -9,10 +10,12 @@ namespace Yi.Framework.AiHub.Domain.Alipay;
public class AlipayManager : DomainService
{
private readonly ILogger _logger;
+ private readonly IConfiguration _configuration;
- public AlipayManager(ILogger logger)
+ public AlipayManager(ILogger logger, IConfiguration configuration)
{
_logger = logger;
+ _configuration = configuration;
}
///
@@ -27,7 +30,7 @@ public class AlipayManager : DomainService
{
// 2. 发起API调用(以创建当面付收款二维码为例)
var response = Factory.Payment.Page()
- .Pay(productName, orderNumber, totalAmount.ToString(), "https://ccnetcore.com/pay/sucess");
+ .Pay(productName, orderNumber, totalAmount.ToString(), _configuration["Alipay:ReturnUrl"]);
// 3. 处理响应或异常
if (ResponseChecker.Success(response))
{
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs
index 316b4e15..4939005b 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/PayManager.cs
@@ -69,7 +69,7 @@ public class PayManager : DomainService
/// 交易状态
/// 支付宝交易号
///
- public async Task UpdateOrderStatusAsync(string outTradeNo, TradeStatusEnum tradeStatus, string? tradeNo = null)
+ public async Task UpdateOrderStatusAsync(string outTradeNo, TradeStatusEnum tradeStatus, string? tradeNo = null)
{
var order = await _payOrderRepository.GetFirstAsync(x => x.OutTradeNo == outTradeNo);
if (order == null)
@@ -84,6 +84,7 @@ public class PayManager : DomainService
}
await _payOrderRepository.UpdateAsync(order);
+ return order;
}
@@ -128,13 +129,10 @@ public class PayManager : DomainService
///
private TradeStatusEnum ParseTradeStatus(string tradeStatus)
{
- return tradeStatus switch
+ if (Enum.TryParse(tradeStatus, out var result))
{
- "WAIT_BUYER_PAY" => TradeStatusEnum.WAIT_BUYER_PAY,
- "TRADE_SUCCESS" => TradeStatusEnum.TRADE_SUCCESS,
- "TRADE_FINISHED" => TradeStatusEnum.TRADE_FINISHED,
- "TRADE_CLOSED" => TradeStatusEnum.TRADE_CLOSED,
- _ => TradeStatusEnum.WAIT_TRADE
- };
+ return result;
+ }
+ return TradeStatusEnum.WAIT_TRADE;
}
}
\ No newline at end of file