Project.Fengling.QoderVersion/Backend/src/Fengling.Backend.Web/Application/Commands/RedemptionOrders/RedemptionOrderCommands.cs
sam 056eb9b6f9 feat: 实现完整的前后端功能
- 后端新增管理员、商品、分类聚合模型
- 实现积分规则、礼品、订单、会员等完整功能
- 添加管理员认证和权限管理
- 完善数据库迁移和实体配置
- 前端管理后台实现登录、仪表盘、积分规则、礼品、订单、会员等页面
- 集成shadcn-vue UI组件库
- 添加前后端功能文档和截图
2026-02-11 21:36:37 +08:00

169 lines
6.1 KiB
C#

using Fengling.Backend.Domain.AggregatesModel.RedemptionOrderAggregate;
using Fengling.Backend.Domain.AggregatesModel.GiftAggregate;
using Fengling.Backend.Domain.AggregatesModel.MemberAggregate;
using Fengling.Backend.Infrastructure.Repositories;
namespace Fengling.Backend.Web.Application.Commands.RedemptionOrders;
/// <summary>
/// 创建兑换订单命令
/// </summary>
public record CreateRedemptionOrderCommand(
MemberId MemberId,
GiftId GiftId,
int Quantity,
CreateRedemptionOrderAddressDto? ShippingAddress = null) : ICommand<RedemptionOrderId>;
public record CreateRedemptionOrderAddressDto(
string ReceiverName,
string Phone,
string Province,
string City,
string District,
string DetailAddress);
public class CreateRedemptionOrderCommandHandler(
IRedemptionOrderRepository redemptionOrderRepository,
IGiftRepository giftRepository,
IMemberRepository memberRepository) : ICommandHandler<CreateRedemptionOrderCommand, RedemptionOrderId>
{
public async Task<RedemptionOrderId> Handle(CreateRedemptionOrderCommand request, CancellationToken cancellationToken)
{
// 1. 获取礼品信息
var gift = await giftRepository.GetByIdAsync(request.GiftId, cancellationToken);
if (gift == null)
throw new KnownException("礼品不存在");
if (!gift.IsOnShelf)
throw new KnownException("礼品已下架");
// 2. 检查库存
if (gift.AvailableStock < request.Quantity)
throw new KnownException($"库存不足,当前可用:{gift.AvailableStock}");
// 3. 检查限兑数量
if (gift.LimitPerMember.HasValue)
{
var redeemedCount = await redemptionOrderRepository.GetMemberRedemptionCountAsync(
request.MemberId.Id, request.GiftId.Id, cancellationToken);
if (redeemedCount + request.Quantity > gift.LimitPerMember.Value)
throw new KnownException($"超出限兑数量,每人限兑{gift.LimitPerMember.Value}个,已兑换{redeemedCount}个");
}
// 4. 获取会员信息并检查积分
var member = await memberRepository.GetAsync(request.MemberId, cancellationToken);
if (member == null)
throw new KnownException("会员不存在");
var consumedPoints = gift.RequiredPoints * request.Quantity;
if (member.AvailablePoints < consumedPoints)
throw new KnownException($"积分不足,需要{consumedPoints}分,当前{member.AvailablePoints}分");
// 5. 扣减积分
member.ConsumePoints(consumedPoints, "兑换礼品", Guid.NewGuid());
await memberRepository.UpdateAsync(member, cancellationToken);
// 6. 构造收货地址
Address? shippingAddress = null;
if (request.ShippingAddress != null)
{
shippingAddress = new Address(
request.ShippingAddress.ReceiverName,
request.ShippingAddress.Phone,
request.ShippingAddress.Province,
request.ShippingAddress.City,
request.ShippingAddress.District,
request.ShippingAddress.DetailAddress);
}
else if (gift.Type == GiftType.Physical)
{
throw new KnownException("实物礼品必须提供收货地址");
}
// 7. 生成订单号
var orderNo = $"RO{DateTime.UtcNow:yyyyMMddHHmmss}{Random.Shared.Next(1000, 9999)}";
// 8. 创建订单
var order = new RedemptionOrder(
orderNo,
request.MemberId.Id,
request.GiftId.Id,
gift.Name,
(int)gift.Type,
request.Quantity,
consumedPoints,
shippingAddress);
await redemptionOrderRepository.AddAsync(order, cancellationToken);
return order.Id;
}
}
/// <summary>
/// 标记订单为已发货命令
/// </summary>
public record MarkOrderAsDispatchedCommand(RedemptionOrderId OrderId, string? TrackingNo = null) : ICommand<ResponseData>;
public class MarkOrderAsDispatchedCommandHandler(
IRedemptionOrderRepository redemptionOrderRepository) : ICommandHandler<MarkOrderAsDispatchedCommand, ResponseData>
{
public async Task<ResponseData> Handle(MarkOrderAsDispatchedCommand request, CancellationToken cancellationToken)
{
var order = await redemptionOrderRepository.GetByIdAsync(request.OrderId, cancellationToken);
if (order == null)
throw new KnownException("订单不存在");
order.MarkAsDispatched(request.TrackingNo);
await redemptionOrderRepository.UpdateAsync(order, cancellationToken);
return new ResponseData();
}
}
/// <summary>
/// 完成订单命令
/// </summary>
public record CompleteOrderCommand(RedemptionOrderId OrderId) : ICommand<ResponseData>;
public class CompleteOrderCommandHandler(
IRedemptionOrderRepository redemptionOrderRepository) : ICommandHandler<CompleteOrderCommand, ResponseData>
{
public async Task<ResponseData> Handle(CompleteOrderCommand request, CancellationToken cancellationToken)
{
var order = await redemptionOrderRepository.GetByIdAsync(request.OrderId, cancellationToken);
if (order == null)
throw new KnownException("订单不存在");
order.Complete();
await redemptionOrderRepository.UpdateAsync(order, cancellationToken);
return new ResponseData();
}
}
/// <summary>
/// 取消订单命令
/// </summary>
public record CancelOrderCommand(RedemptionOrderId OrderId, string Reason) : ICommand<ResponseData>;
public class CancelOrderCommandHandler(
IRedemptionOrderRepository redemptionOrderRepository) : ICommandHandler<CancelOrderCommand, ResponseData>
{
public async Task<ResponseData> Handle(CancelOrderCommand request, CancellationToken cancellationToken)
{
var order = await redemptionOrderRepository.GetByIdAsync(request.OrderId, cancellationToken);
if (order == null)
throw new KnownException("订单不存在");
order.Cancel(request.Reason);
await redemptionOrderRepository.UpdateAsync(order, cancellationToken);
return new ResponseData();
}
}