From 25746344595810d2bda218c7d35b47771ad751f8 Mon Sep 17 00:00:00 2001 From: Sam <315859133@qq.com> Date: Mon, 9 Feb 2026 19:06:08 +0800 Subject: [PATCH] feat: add points rule endpoints --- .../PointsRuleModel/PointsRuleConditionId.cs | 4 + .../PointsRuleModel/PointsRuleId.cs | 4 + .../Endpoints/v1/PointsRuleEndpoints.cs | 171 ++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 src/Fengling.Member.Web/Endpoints/v1/PointsRuleEndpoints.cs diff --git a/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleConditionId.cs b/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleConditionId.cs index 12f80ec..995b2a6 100644 --- a/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleConditionId.cs +++ b/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleConditionId.cs @@ -3,4 +3,8 @@ namespace Fengling.Member.Domain.Aggregates.PointsRuleModel; public partial record PointsRuleConditionId : IGuidStronglyTypedId { public static PointsRuleConditionId New() => new(Guid.NewGuid()); + + public Guid Value => this; + + public static implicit operator Guid(PointsRuleConditionId id) => id.Value; } diff --git a/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleId.cs b/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleId.cs index 228971a..f6d06ba 100644 --- a/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleId.cs +++ b/src/Fengling.Member.Domain/Aggregates/PointsRuleModel/PointsRuleId.cs @@ -3,4 +3,8 @@ namespace Fengling.Member.Domain.Aggregates.PointsRuleModel; public partial record PointsRuleId : IGuidStronglyTypedId { public static PointsRuleId New() => new(Guid.NewGuid()); + + public Guid Value => this; + + public static implicit operator Guid(PointsRuleId id) => id.Value; } diff --git a/src/Fengling.Member.Web/Endpoints/v1/PointsRuleEndpoints.cs b/src/Fengling.Member.Web/Endpoints/v1/PointsRuleEndpoints.cs new file mode 100644 index 0000000..e5143fe --- /dev/null +++ b/src/Fengling.Member.Web/Endpoints/v1/PointsRuleEndpoints.cs @@ -0,0 +1,171 @@ +using FastEndpoints; +using Fengling.Member.Application.Commands.Points; +using Fengling.Member.Application.Dtos; +using Fengling.Member.Application.Dtos.PointsRule; +using Fengling.Member.Domain.Aggregates.PointsRuleModel; +using Fengling.Member.Domain.Repositories; +using MediatR; + +namespace Fengling.Member.Web.Endpoints.v1; + +public class QueryPointsRulesEndpoint : Endpoint> +{ + private readonly IPointsRuleRepository _ruleRepository; + + public QueryPointsRulesEndpoint(IPointsRuleRepository ruleRepository) + { + _ruleRepository = ruleRepository; + } + + public override void Configure() + { + Get("/api/v1/points-rules"); + Summary(s => + { + s.Summary = "查询积分规则列表"; + s.Description = "获取所有启用的积分规则"; + }); + } + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var rules = await _ruleRepository.GetActiveRulesAsync(); + + var result = rules.Select(r => new PointsRuleDto( + Id: r.Id, + Name: r.Name, + Code: r.Code, + RuleType: r.RuleType, + BasePoints: r.BasePoints, + WeightFactor: r.WeightFactor, + ValidityDays: r.ValidityDays, + Priority: r.Priority, + CalculationMode: r.CalculationMode, + IsActive: r.IsActive, + EffectiveFrom: r.EffectiveFrom, + EffectiveTo: r.EffectiveTo, + Conditions: r.Conditions.Select(c => new PointsRuleConditionDto( + Id: c.Id, + RuleId: c.RuleId, + DimensionType: c.DimensionType, + DimensionValue: c.DimensionValue, + Operator: c.Operator + )).ToList() + )).ToList(); + + Response = result; + } +} + +public class CreatePointsRuleEndpoint : Endpoint +{ + private readonly IPointsRuleRepository _ruleRepository; + private readonly IPointsRuleConditionRepository _conditionRepository; + + public CreatePointsRuleEndpoint( + IPointsRuleRepository ruleRepository, + IPointsRuleConditionRepository conditionRepository) + { + _ruleRepository = ruleRepository; + _conditionRepository = conditionRepository; + } + + public override void Configure() + { + Post("/api/v1/points-rules"); + Summary(s => + { + s.Summary = "创建积分规则"; + s.Description = "创建新的积分规则并配置条件"; + }); + } + + public override async Task HandleAsync(CreatePointsRuleRequest req, CancellationToken ct) + { + var rule = PointsRule.Create( + req.Name, + req.Code, + req.RuleType, + req.BasePoints, + req.ValidityDays, + req.Priority, + req.CalculationMode, + req.WeightFactor); + + await _ruleRepository.AddAsync(rule); + + foreach (var condition in req.Conditions) + { + var ruleCondition = PointsRuleCondition.Create( + rule.Id, + condition.DimensionType, + condition.DimensionValue, + condition.Operator); + + await _conditionRepository.AddAsync(ruleCondition); + } + + var response = new CreatePointsRuleResponse( + Id: rule.Id, + Name: rule.Name, + Code: rule.Code + ); + + HttpContext.Response.Headers.Location = $"/api/v1/points-rules/{rule.Id}"; + Response = response; + HttpContext.Response.StatusCode = 201; + } +} + +public record CalculatePointsRequest( + string ProductId, + string ProductName, + string? ProductPrice, + string DealerId, + string DistributorId, + string StoreId, + string CodeId +) : IRequest; + +public class CalculatePointsEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public CalculatePointsEndpoint(IMediator mediator) + { + _mediator = mediator; + } + + public override void Configure() + { + Post("/api/v1/points-rules/calculate"); + Summary(s => + { + s.Summary = "计算积分"; + s.Description = "根据扫码信息计算应发积分"; + }); + } + + public override async Task HandleAsync(CalculatePointsRequest req, CancellationToken ct) + { + var command = new CalculatePointsCommand(new CodeInfoDto( + ProductId: req.ProductId, + ProductName: req.ProductName, + ProductPrice: req.ProductPrice, + DealerId: req.DealerId, + DistributorId: req.DistributorId, + StoreId: req.StoreId, + CodeId: req.CodeId + )); + + var result = await _mediator.Send(command, ct); + + Response = result; + } +} + +public record CreatePointsRuleResponse( + Guid Id, + string Name, + string Code +);