- 后端新增管理员、商品、分类聚合模型 - 实现积分规则、礼品、订单、会员等完整功能 - 添加管理员认证和权限管理 - 完善数据库迁移和实体配置 - 前端管理后台实现登录、仪表盘、积分规则、礼品、订单、会员等页面 - 集成shadcn-vue UI组件库 - 添加前后端功能文档和截图
18 KiB
后端功能概览
本文档说明当前后端(Backend)已完成的主要功能与技术实现,便于后续开发和前后端联调。
最后更新时间:2026-02-11
一、整体技术栈与架构
1.1 技术栈
- .NET 10 - 最新的 .NET 运行时
- EF Core + SQLite - 数据持久化(已从 PostgreSQL 迁移到 SQLite)
- CAP + NetCorePal - 分布式事务与集成事件框架
- FastEndpoints - 高性能 API 端点框架
- Hangfire - 后台任务调度
- Redis - 分布式缓存与 CAP 消息存储
- MediatR - CQRS 模式实现
- Swashbuckle/Swagger - API 文档
1.2 架构风格
- CleanDDD 分层结构:Domain / Infrastructure / Web
- 聚合根:统一继承
Entity<TId>, IAggregateRoot - 强类型 ID:所有实体 ID 使用
xxxId : IGuidStronglyTypedId - 领域事件 + 集成事件:解耦跨聚合、跨事务操作
- CQRS:命令(Command)与查询(Query)分离,命令处理器操作仓储,查询直接访问 DbContext
- 最终一致性:通过领域事件 → 集成事件 → 事件处理器实现
二、已完成的核心聚合与领域模型
2.1 会员聚合 (MemberAggregate)
- 实体:
Member - 核心字段:
- 手机号、密码(加密)、昵称
- 累计总积分
TotalPoints - 可用积分
AvailablePoints - 状态(正常/禁用)、注册时间
- 值对象:
MemberLevel:等级编码、名称、所需积分、积分倍率
- 领域行为:
AddPoints(amount, source, reason, relatedId, expiryDate)- 增加积分ConsumePoints(amount, reason, orderId)- 消费积分RefundPoints(amount, reason, orderId)- 退还积分
- 领域事件:
PointsAddedDomainEventPointsConsumedDomainEventPointsRefundedDomainEvent
2.2 营销码聚合 (MarketingCodeAggregate)
- 实体:
MarketingCode - 核心字段:
- 营销码
Code(唯一) - 批次号
BatchNo - 是否已使用
IsUsed - 使用者会员ID、使用时间
- 过期时间
- 营销码
- 值对象:
ProductInfo:产品ID、产品名称、品类ID、品类名称
- 领域行为:
Use(memberId)- 使用营销码
- 领域事件:
MarketingCodeUsedDomainEvent
2.3 积分规则聚合 (PointsRuleAggregate)
- 实体:
PointsRule - 核心字段:
- 规则名称、规则类型(产品/时间/会员等级)
- 积分值、奖励倍数
- 产品ID、品类ID、会员等级编码
- 生效时间范围(开始/结束)
- 是否激活
- 领域行为:
CalculatePoints(memberBonusRate)- 计算应得积分
2.4 积分交易聚合 (PointsTransactionAggregate)
- 实体:
PointsTransaction - 核心字段:
- 会员ID、交易类型(获取/消费/退还/过期)
- 积分数量、来源、原因描述
- 关联ID(营销码ID/订单ID等)
- 过期时间(仅获取类型有效)
- 创建时间
- 静态工厂方法:
CreateEarnTransaction(...)- 创建获取积分记录CreateConsumeTransaction(...)- 创建消费积分记录CreateRefundTransaction(...)- 创建退还积分记录CreateExpireTransaction(...)- 创建过期积分记录
- 说明:通过集成事件异步创建,与会员聚合解耦
2.5 礼品聚合 (GiftAggregate)
- 实体:
Gift - 核心字段:
- 礼品名称、类型(实物/虚拟/自有产品)
- 描述、图片URL
- 所需积分、总库存、可用库存
- 每人限兑数量、是否上架、排序
- 创建/更新时间
- 领域行为:
Update(...)- 更新礼品信息AddStock(quantity)- 增加库存ReserveStock(quantity)- 预留库存(下单时)DeductStock(quantity)- 扣减总库存(发货时)ReleaseStock(quantity)- 释放库存(订单取消时)PutOnShelf()/PutOffShelf()- 上架/下架
- 领域事件:
GiftCreatedDomainEventGiftUpdatedDomainEventGiftStockChangedDomainEvent
2.6 兑换订单聚合 (RedemptionOrderAggregate)
- 实体:
RedemptionOrder - 核心字段:
- 订单号、会员ID、礼品ID/名称/类型
- 数量、消耗积分
- 物流单号、取消原因
- 状态(待处理/已发货/已送达/已完成/已取消)
- 创建/更新时间
- 值对象:
Address:收货人姓名、电话、省市区、详细地址(实物礼品必填)
- 领域行为:
MarkAsDispatched(trackingNo)- 标记为已发货MarkAsDelivered()- 标记为已送达Complete()- 完成订单Cancel(reason)- 取消订单
- 领域事件:
RedemptionOrderCreatedDomainEventRedemptionOrderDispatchedDomainEventRedemptionOrderDeliveredDomainEventRedemptionOrderCompletedDomainEventRedemptionOrderCancelledDomainEvent
三、核心业务流程
3.1 会员注册与登录
会员注册
- 端点:
POST /api/members/register - 请求:
RegisterMemberRequest { Phone, Password, Nickname? } - 命令:
RegisterMemberCommand - 流程:
- 校验手机号唯一性
- 密码加密存储
- 创建会员并设置初始等级
- 返回会员ID
会员登录
- 端点:
POST /api/members/login - 请求:
LoginMemberRequest { Phone, Password } - 命令:
LoginMemberCommand - 流程:
- 验证手机号和密码
- 返回会员信息和 Token(TODO: 完善 JWT 认证)
3.2 扫码获取积分流程
使用营销码
- 端点:
POST /api/marketing-codes/scan - 请求:
UseMarketingCodeRequest { Code, MemberId } - 命令:
UseMarketingCodeCommand
完整流程
1. UseMarketingCodeCommand
├─ 校验营销码存在且未使用
├─ 校验未过期
├─ 关联会员并标记为已使用
└─ 发布 MarketingCodeUsedDomainEvent
2. MarketingCodeUsedDomainEvent
└─ MarketingCodeUsedDomainEventHandlerForEarnPoints
├─ 加载会员聚合
├─ 匹配积分规则(IPointsRuleRepository.GetEffectiveRulesAsync)
├─ 计算应得积分和过期时间
├─ 调用 Member.AddPoints(...)
├─ 更新会员聚合
└─ 发布 PointsAddedDomainEvent
3. PointsAddedDomainEvent
└─ PointsAddedToPointsEarnedConverter (集成事件转换器)
└─ 发布 PointsEarnedIntegrationEvent
4. PointsEarnedIntegrationEvent
└─ PointsEarnedIntegrationEventHandler
├─ 幂等性检查(基于 RelatedId)
├─ 创建 PointsTransaction.CreateEarnTransaction(...)
└─ 保存到积分交易表
3.3 礼品兑换流程
创建兑换订单
- 端点:
POST /api/gifts/redeem - 请求:
CreateRedemptionOrderCommand { MemberId, GiftId, Quantity, ShippingAddress? }
完整流程
1. CreateRedemptionOrderCommand
├─ 校验礼品存在且已上架
├─ 校验库存充足
├─ 校验限兑数量(IRedemptionOrderRepository.GetMemberRedemptionCountAsync)
├─ 校验会员积分充足
├─ 调用 Member.ConsumePoints(...) 扣减积分
├─ 更新会员聚合 → 发布 PointsConsumedDomainEvent
├─ 构造收货地址(实物礼品必填)
├─ 创建 RedemptionOrder 聚合
└─ 发布 RedemptionOrderCreatedDomainEvent
2. PointsConsumedDomainEvent
└─ PointsConsumedToPointsConsumedIntegrationEventConverter
└─ 发布 PointsConsumedIntegrationEvent
└─ 创建消费积分交易记录
3. RedemptionOrderCreatedDomainEvent
└─ RedemptionOrderCreatedDomainEventHandler
├─ 加载礼品聚合
├─ 调用 Gift.ReserveStock(quantity)
└─ 更新礼品聚合(预留库存)
订单状态流转
订单发货: POST /api/admin/redemption-orders/{OrderId}/dispatch
├─ MarkOrderAsDispatchedCommand
├─ Order.MarkAsDispatched(trackingNo)
├─ 发布 RedemptionOrderDispatchedDomainEvent
└─ RedemptionOrderDispatchedDomainEventHandler
└─ Gift.DeductStock(quantity) 扣减总库存
订单取消: POST /api/admin/redemption-orders/{OrderId}/cancel
├─ CancelOrderCommand
├─ Order.Cancel(reason)
├─ 发布 RedemptionOrderCancelledDomainEvent
├─ RedemptionOrderCancelledDomainEventHandler
│ └─ Gift.ReleaseStock(quantity) 释放库存
└─ 退还积分(TODO: 待实现)
四、积分交易与集成事件架构
4.1 领域事件与集成事件流转
领域事件 (Domain Events)
在会员聚合中发布,用于触发同一事务内或跨事务的业务逻辑:
PointsAddedDomainEvent- 会员增加积分时PointsConsumedDomainEvent- 会员消费积分时PointsRefundedDomainEvent- 积分退还时PointsExpiredDomainEvent- 积分过期时
集成事件 (Integration Events)
实现 IIntegrationEvent 接口,通过 CAP 框架发布和消费:
PointsEarnedIntegrationEvent- 对应 Earn 交易PointsConsumedIntegrationEvent- 对应 Consume 交易PointsRefundedIntegrationEvent- 对应 Refund 交易PointsExpiredIntegrationEvent- 对应 Expire 交易
集成事件转换器 (IIntegrationEventConverter)
将领域事件转换为集成事件:
PointsAddedToPointsEarnedConverterPointsConsumedToPointsConsumedIntegrationEventConverterPointsRefundedToPointsRefundedIntegrationEventConverterPointsExpiredToPointsExpiredIntegrationEventConverter
4.2 集成事件处理器
位于 Web 层,通过 ApplicationDbContext 操作积分交易表:
// 示例:处理获取积分集成事件
public class PointsEarnedIntegrationEventHandler : IIntegrationEventHandler<PointsEarnedIntegrationEvent>
{
public async Task Handle(PointsEarnedIntegrationEvent @event, CancellationToken cancellationToken)
{
// 1. 幂等性检查:基于 RelatedId 查询是否已存在
var exists = await dbContext.PointsTransactions
.AnyAsync(x => x.RelatedId == @event.RelatedId, cancellationToken);
if (exists) return; // 已处理过,跳过
// 2. 创建积分交易记录
var transaction = PointsTransaction.CreateEarnTransaction(
memberId: new MemberId(@event.MemberId),
amount: @event.Amount,
source: @event.Source,
reason: @event.Reason,
relatedId: @event.RelatedId,
expiryDate: @event.ExpiryDate
);
// 3. 保存到数据库
await dbContext.PointsTransactions.AddAsync(transaction, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
}
}
4.3 事务与一致性保证
最终一致性
- 会员积分变更(会员聚合)和 积分交易记录(PointsTransaction 聚合)处于不同事务
- 通过 领域事件 → 集成事件 → 事件处理器 链路实现最终一致性
- CAP 框架保证集成事件至少一次送达
幂等性保证
- 基于
RelatedId(营销码ID、订单ID等)进行幂等性检查 - 防止重复消费导致的数据不一致
五、API 端点一览
5.1 会员模块 (Members)
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/members/register |
POST | 会员注册 | 匿名 |
/api/members/login |
POST | 会员登录 | 匿名 |
/api/members/{MemberId} |
GET | 获取会员信息 | 需要 |
5.2 营销码模块 (MarketingCodes)
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/marketing-codes/scan |
POST | 扫码使用营销码 | 匿名 |
/api/admin/marketing-codes/generate |
POST | 批量生成营销码(管理端) | 需要 |
5.3 礼品模块 (Gifts)
会员端
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/gifts |
GET | 获取上架礼品列表 | 匿名 |
/api/gifts/{GiftId} |
GET | 获取礼品详情 | 匿名 |
/api/gifts/redeem |
POST | 兑换礼品 | 需要 |
管理端
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/admin/gifts |
POST | 创建礼品 | 需要 |
/api/admin/gifts/{GiftId} |
PUT | 更新礼品信息 | 需要 |
/api/admin/gifts/{GiftId}/putonshelf |
POST | 上架礼品 | 需要 |
/api/admin/gifts/{GiftId}/putoffshelf |
POST | 下架礼品 | 需要 |
/api/admin/gifts/{GiftId}/addstock |
POST | 增加库存 | 需要 |
/api/admin/gifts |
GET | 获取礼品列表(支持筛选) | 需要 |
/api/admin/gifts/{GiftId} |
GET | 获取礼品详情 | 需要 |
5.4 兑换订单模块 (RedemptionOrders)
会员端
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/redemption-orders/my |
GET | 获取我的兑换订单列表 | 需要 |
/api/redemption-orders/{OrderId} |
GET | 获取订单详情 | 需要 |
管理端
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/admin/redemption-orders |
GET | 获取兑换订单列表 | 需要 |
/api/admin/redemption-orders/{OrderId} |
GET | 获取订单详情 | 需要 |
/api/admin/redemption-orders/{OrderId}/dispatch |
POST | 标记为已发货 | 需要 |
/api/admin/redemption-orders/{OrderId}/complete |
POST | 完成订单 | 需要 |
/api/admin/redemption-orders/{OrderId}/cancel |
POST | 取消订单 | 需要 |
5.5 积分规则模块 (PointsRules)
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/admin/points-rules |
POST | 创建积分规则(管理端) | 需要 |
5.6 通用端点
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/hello |
GET | 健康检查 | 匿名 |
/swagger |
GET | API 文档 | 匿名 |
注意:
- 所有端点返回统一的
ResponseData<T>格式 - 强类型ID(如
MemberId,GiftId)在 Swagger 中映射为字符串类型 - 当前 JWT 认证尚未完全实现,部分端点暂时从请求参数获取 MemberId
六、数据库设计
6.1 数据库信息
- 数据库类型:SQLite
- 数据库文件:
app.db(开发环境) - 迁移工具:EF Core Migrations
- 最新迁移:
20260211044819_Init
6.2 核心数据表
Members - 会员表
主要字段:Id, Phone(唯一), Password, Nickname, Status, TotalPoints, AvailablePoints, LevelCode, LevelName, BonusRate, RequiredPoints, RegisteredAt
MarketingCodes - 营销码表
主要字段:Id, Code(唯一), BatchNo, IsUsed, UsedByMemberId, UsedAt, ExpiryDate, ProductId, ProductName, CategoryId, CategoryName
PointsRules - 积分规则表
主要字段:Id, RuleName, RuleType, PointsValue, BonusMultiplier, ProductId, CategoryId, MemberLevelCode, StartDate, EndDate, IsActive
PointsTransactions - 积分交易表
主要字段:Id, MemberId, Type, Amount, Source, Reason, RelatedId, ExpiryDate, CreatedAt
重要索引:
IX_PointsTransactions_MemberId- 会员积分查询IX_PointsTransactions_RelatedId- 幂等性检查(非唯一)IX_PointsTransactions_Type- 按类型筛选IX_PointsTransactions_CreatedAt- 时间排序
Gifts - 礼品表
主要字段:Id, Name, Type, Description, ImageUrl, RequiredPoints, TotalStock, AvailableStock, LimitPerMember, IsOnShelf, SortOrder, CreatedAt, UpdatedAt
RedemptionOrders - 兑换订单表
主要字段:Id, OrderNo(唯一), MemberId, GiftId, GiftName, GiftType, Quantity, ConsumedPoints, Status, TrackingNo, CancelReason, ReceiverName, ReceiverPhone, Province, City, District, DetailAddress, CreatedAt, UpdatedAt
6.3 数据表关系说明
- 所有表使用 GUID(Version 7)作为主键
- 使用软删除(
Deleted字段) - 使用行版本(
RowVersion)实现乐观并发控制 - 积分交易表与会员表通过 MemberId 关联,但不设置外键(最终一致性)
- 兑换订单表包含礼品快照信息,减少关联查询
七、当前状态与后续建议
7.1 当前状态
✅ 已完成功能:
- 后端项目成功编译和运行(
dotnet build&dotnet run) - 数据库迁移已修复(SQLite 切换完成,EF Core 模型与迁移一致)
- Swagger API 文档正常生成(Schema 冲突已解决)
- 会员、营销码、积分规则、积分交易、礼品、兑换订单等核心领域模型完整
- 扫码获取积分、礼品兑换等主要业务流程已打通
- 集成事件架构实现(领域事件 → 集成事件 → 事件处理器)
⚠️ 已知问题:
- 存在若干 Sonar 质量规则警告(TODO 注释、异常处理建议等),不影响运行
- JWT 认证尚未完全实现,部分端点暂时从请求参数获取 MemberId
- 订单取消后的积分退还逻辑待完善
7.2 后续建议
短期优化
-
完善认证鉴权
- 实现完整的 JWT Token 认证流程
- 从 Token 中获取当前登录会员ID
- 添加基于角色的权限控制(会员端/管理端)
-
补充查询功能
- 会员积分流水查询(分页、筛选)
- 礼品库存统计和销售报表
- 订单统计和数据分析
-
完善业务逻辑
- 实现订单取消后的积分退还
- 添加积分过期处理定时任务
- 完善会员等级自动升级逻辑
长期规划
- 根据前端实际需求调整 API 结构和 DTO 字段
- 增加单元测试和集成测试覆盖率
- 性能优化和缓存策略
- 监控和日志完善
八、开发与部署
8.1 本地开发
# 启动基础设施(Redis)
cd Backend/scripts
./init-infrastructure.sh # Linux/Mac
./init-infrastructure.ps1 # Windows
# 运行后端
cd Backend/src/Fengling.Backend.Web
dotnet run
# 访问 Swagger 文档
http://localhost:5511/swagger
8.2 数据库迁移
# 添加新迁移
cd Backend/src/Fengling.Backend.Infrastructure
dotnet ef migrations add MigrationName
# 应用迁移(自动在启动时执行)
dotnet ef database update
8.3 项目结构
Backend/
├── src/
│ ├── Fengling.Backend.Domain/ # 领域层:聚合、实体、值对象、领域事件
│ ├── Fengling.Backend.Infrastructure/ # 基础设施层:数据库、仓储实现
│ └── Fengling.Backend.Web/ # 应用层:API端点、命令查询、事件处理器
├── test/ # 测试项目
└── scripts/ # 基础设施脚本