增加Mediat Pip特性,并用实例来做一个demo
This commit is contained in:
1 parent
292cb8638c
commit
c9ac7412ab
19 files changed
+682
-108
No files matched your search
@@ -1,81 +1,146 @@
|
||||
//using MediatR;
|
||||
//using Store.Framework.Models;
|
||||
//using Store.Shops.Contracts;
|
||||
//using Store.Users.Contracts.Dtos;
|
||||
//using Store.Users.Entities;
|
||||
//using Store.Users.Repositories;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using YourNamespace;
|
||||
using MAX.Framework.Mediation;
|
||||
using MAX.Core.Mediation;
|
||||
using Store.Users.Behaviors;
|
||||
using MAX.Core.Helpers;
|
||||
using MAX.Framework.Commons;
|
||||
using MediatR;
|
||||
using Store.Users.Contracts.Dtos;
|
||||
using Store.Users.Entities;
|
||||
|
||||
//namespace Store.Users.Commands
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 商铺续费
|
||||
// /// </summary>
|
||||
// /// <param name="UserName"></param>
|
||||
// /// <param name="ShopId"></param>
|
||||
// /// <param name="RenewDuration"></param>
|
||||
// internal record class ShopRenewCommand(string UserName, string ShopId, int RenewDuration) : IRequest<ShopRenewResponse>;
|
||||
// internal class ShopRenewCommandHandler : IRequestHandler<ShopRenewCommand, ShopRenewResponse>
|
||||
// {
|
||||
// private readonly IUserRepository _userRepository;
|
||||
// private readonly IShopQueryService _shopQueryService;
|
||||
namespace Store.Users.Commands;
|
||||
|
||||
// public ShopRenewCommandHandler(IUserRepository userRepository, IShopQueryService shopQueryService)
|
||||
// {
|
||||
// _userRepository = userRepository;
|
||||
// _shopQueryService = shopQueryService;
|
||||
// }
|
||||
// async Task<ShopRenewResponse> IRequestHandler<ShopRenewCommand, ShopRenewResponse>.Handle(ShopRenewCommand request, CancellationToken cancellationToken)
|
||||
// {
|
||||
// ShopRenewResponse response = new ShopRenewResponse();
|
||||
// var user = await _userRepository.GetUser(request.UserName);
|
||||
// int shopPointsPerMonth = Math.Max(30, user.ShopPointsPerMonth);
|
||||
// int deltaPoints = shopPointsPerMonth * request.RenewDuration;
|
||||
// int newPoints = (int)user.Points - deltaPoints;
|
||||
// DateTime expireTime = _shopQueryService.GetExpireTime(request.ShopId);
|
||||
/// <summary>商铺续费,续费时长单位为月。</summary>
|
||||
[MediatRBehavior(typeof(ValidationBehavior<,>))]
|
||||
[MediatRBehavior(typeof(TransactionBehavior<,>))]
|
||||
[MediatRBehavior(typeof(AccountConsumptionBehavior<,>))]
|
||||
[MediatRBehavior(typeof(ShopOwnershipBehavior<,>))]
|
||||
public sealed record ShopRenewCommand(string UserName, string ShopId, int RenewDuration, string? Remark = null)
|
||||
: IRequest<ShopRenewResponse>, IValidatableRequest, IAccountConsumptionRequest, IShopOwnershipRequest
|
||||
{
|
||||
// 由消费管道建立,仅在当前事务执行期间有效。
|
||||
AccountConsumptionContext? IAccountConsumptionRequest.ConsumptionContext { get; set; }
|
||||
ShopEntity? IShopOwnershipRequest.OwnedShop { get; set; }
|
||||
|
||||
void IValidatableRequest.Validate()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(UserName) || UserName.Trim().Length > 20)
|
||||
throw new ValidationException("用户名不能为空且长度不能超过20个字符");
|
||||
if (string.IsNullOrWhiteSpace(ShopId) || ShopId.Trim().Length > 50)
|
||||
throw new ValidationException("店铺ID不能为空且长度不能超过50个字符");
|
||||
if (RenewDuration is < 1 or > 120)
|
||||
throw new ValidationException("续费时长必须为1-120个月");
|
||||
if (Remark?.Trim().Length > 255)
|
||||
throw new ValidationException("备注长度不能超过255个字符");
|
||||
}
|
||||
|
||||
ConsumptionQuote IAccountConsumptionRequest.CalculateConsumption(UserEntity user)
|
||||
{
|
||||
if (RenewDuration is < 1 or > 120)
|
||||
throw new AppException("续费时长必须为1-120个月");
|
||||
int price = Math.Max(30, user.ShopPointsPerMonth);
|
||||
return new ConsumptionQuote((decimal)price * RenewDuration, price);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ShopRenewCommandHandler(UnitOfWorkExecutionContext executionContext)
|
||||
: IRequestHandler<ShopRenewCommand, ShopRenewResponse>
|
||||
{
|
||||
public async Task<ShopRenewResponse> Handle(ShopRenewCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var userName = request.UserName.Trim();
|
||||
var shopId = request.ShopId.Trim();
|
||||
var remark = string.IsNullOrWhiteSpace(request.Remark) ? null : request.Remark.Trim();
|
||||
|
||||
var context = ((IAccountConsumptionRequest)request).ConsumptionContext
|
||||
?? throw new InvalidOperationException("续费命令必须通过账户消费管道执行");
|
||||
var orm = executionContext.Orm;
|
||||
var user = context.User;
|
||||
var shop = ((IShopOwnershipRequest)request).OwnedShop
|
||||
?? throw new InvalidOperationException("续费命令必须通过商铺归属管道执行");
|
||||
decimal pointsPerMonth = context.Quote.UnitPrice;
|
||||
decimal cost = context.Quote.Amount;
|
||||
decimal newPoints = user.Points - cost;
|
||||
var now = DateTime.Now;
|
||||
var currentExpire = await orm.Select<ShopExpireEntity>().Where(a => a.ShopId == shopId)
|
||||
.FirstAsync(cancellationToken);
|
||||
var expireBase = now;
|
||||
if (currentExpire is { ExpireTime: > 0 })
|
||||
{
|
||||
var currentTime = DateHelper.ConvertFromUnixTimestampInSeconds(currentExpire.ExpireTime);
|
||||
if (currentTime > expireBase)
|
||||
expireBase = currentTime;
|
||||
}
|
||||
int newExpireTime = CalculateNewExpireTime(expireBase, request.RenewDuration);
|
||||
|
||||
|
||||
// if (currentExpire != null && currentExpire.ExpireTime > 0)
|
||||
// {
|
||||
// DateTime currentExpireTime = TimeUtils.StampToDateTime(currentExpire.ExpireTime);
|
||||
// if (currentExpireTime > expireBaseTime)
|
||||
// {
|
||||
// expireBaseTime = currentExpireTime;
|
||||
// }
|
||||
// }
|
||||
int affected = await orm.Update<UserEntity>().Set(a => a.Points, newPoints)
|
||||
.Where(a => a.Id == user.Id && a.Points == user.Points)
|
||||
.ExecuteAffrowsAsync(cancellationToken);
|
||||
if (affected != 1)
|
||||
throw new AppException("账户已发生改变,请刷新账户后重新操作");
|
||||
|
||||
// int newExpireTime = CalculateNewExpireTime(expireBaseTime, request.RenewDuration);
|
||||
for (int i = 0; i < request.RenewDuration; i++)
|
||||
{
|
||||
var record = new UserPointsRecordEntity
|
||||
{
|
||||
OptionType = "续费",
|
||||
OperatorType = "用户",
|
||||
OperatorName = userName,
|
||||
UserName = userName,
|
||||
UserNick = user.NickName,
|
||||
DeltaPoints = pointsPerMonth,
|
||||
NewPoints = user.Points - (decimal)pointsPerMonth * (i + 1),
|
||||
ShopId = shop.ShopId,
|
||||
ShopAccount = shop.ShopAccount,
|
||||
Remark = remark,
|
||||
AddTime = now.AddSeconds(i)
|
||||
};
|
||||
if (await orm.Insert(record).ExecuteAffrowsAsync(cancellationToken) != 1)
|
||||
throw new AppException("新增操作记录失败,请稍候重试");
|
||||
}
|
||||
|
||||
if (currentExpire == null)
|
||||
{
|
||||
affected = await orm.Insert(new ShopExpireEntity
|
||||
{
|
||||
ShopId = shopId,
|
||||
ExpireTime = newExpireTime,
|
||||
AddTime = now,
|
||||
MdyTime = now
|
||||
}).ExecuteAffrowsAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
affected = await orm.Update<ShopExpireEntity>()
|
||||
.Set(a => a.ExpireTime, newExpireTime).Set(a => a.MdyTime, now)
|
||||
.Where(a => a.Id == currentExpire.Id && a.ExpireTime == currentExpire.ExpireTime)
|
||||
.ExecuteAffrowsAsync(cancellationToken);
|
||||
}
|
||||
if (affected != 1)
|
||||
throw new AppException("更新商铺过期时间失败,请刷新店铺后重新操作");
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new ShopRenewResponse { ShopId = shopId, UserPoints = newPoints, ExpireTime = newExpireTime };
|
||||
}
|
||||
|
||||
// response.ShopId = request.ShopId;
|
||||
// response.UserPoints = newPoints;
|
||||
// response.ExpireTime = newExpireTime;
|
||||
// return response;
|
||||
// }
|
||||
// private int CalculateNewExpireTime(DateTime expireBaseTime, int renewDuration)
|
||||
// {
|
||||
// DateTime newExpireDateTime;
|
||||
// try
|
||||
// {
|
||||
// newExpireDateTime = expireBaseTime.AddMonths(renewDuration);
|
||||
// }
|
||||
// catch (ArgumentOutOfRangeException)
|
||||
// {
|
||||
// throw new InvalidOperationException("续费时长超出允许范围");
|
||||
// }
|
||||
|
||||
// if (newExpireDateTime > TimeUtils.StampToDateTime(int.MaxValue))
|
||||
// {
|
||||
// throw new InvalidOperationException("续费时间超出系统支持范围");
|
||||
// }
|
||||
|
||||
// return TimeUtils.DateTimeToTimestampSeconds(newExpireDateTime);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
//}
|
||||
private static int CalculateNewExpireTime(DateTime expireBase, int duration)
|
||||
{
|
||||
DateTime newExpireDate;
|
||||
try
|
||||
{
|
||||
newExpireDate = expireBase.AddMonths(duration);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
throw new AppException("续费时长超出允许范围");
|
||||
}
|
||||
long timestamp = DateHelper.GetUnixTimestampInSeconds(newExpireDate);
|
||||
if (timestamp > int.MaxValue || timestamp < 0)
|
||||
throw new AppException("续费时间超出系统支持范围");
|
||||
return (int)timestamp;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user