文档目录
积分系统

简介

本开发文档面向 DouPHP 小程序积分系统,围绕“获取、消耗、查询”三大核心能力展开,覆盖以下主题:

  • 积分规则配置与管理:获取条件(如消费返积分)、消耗场景(如积分兑换)、比例参数等。
  • 积分账户数据结构:积分流水表、余额快照、历史记录与等级关联的业务逻辑。
  • 完整功能示例:签到得积分、消费返积分、积分兑换等关键流程的代码路径说明。
  • 统计与报表:积分趋势、使用排行、兑换记录等数据分析思路。
  • 用户体验:积分变化动画、获得提示、使用建议等交互优化建议。

项目结构

积分系统在项目中按端分层组织:

  • API 层:提供小程序端接口,包含积分商城商品列表、用户积分记录查询等。
  • 前台服务层:封装积分商城业务逻辑(商品分页、详情、积分日志列表)。
  • 后台管理:积分流水查看、批量操作、参数设置入口。
  • 钱包服务:统一的积分写入与余额同步(带行锁),确保并发安全。
  • 订单联动:付款成功后按金额比例发放积分;下单时支持积分抵扣。
graph TB
subgraph "小程序前端"
MP["小程序页面"]
end
subgraph "API 层"
API_Point["积分商城控制器"]
API_User["用户积分控制器"]
end
subgraph "前台服务"
F_PointSvc["积分服务 PointService"]
end
subgraph "后台管理"
Admin_PointCtrl["后台积分控制器"]
Admin_PointModel["积分模型 Point"]
end
subgraph "核心服务"
Wallet["钱包服务 WalletService"]
OrderTrans["订单状态机 OrderStatusTransition"]
Checkout["结账服务 CheckoutService"]
end
MP --> API_Point
MP --> API_User
API_Point --> F_PointSvc
API_User --> F_PointSvc
Admin_PointCtrl --> Admin_PointModel
OrderTrans --> Wallet
Checkout --> Wallet

核心组件

  • 钱包服务 WalletService:负责写入积分流水并同步用户余额快照,采用行锁保证并发安全,支持负数扣减校验。
  • 订单状态机 OrderStatusTransition:在订单支付成功后,根据配置的比例计算并派发积分,同时避免重复发放。
  • 结账服务 CheckoutService:在积分抵扣模式下,先扣积分再进入后续下单流程,失败则回滚。
  • 前台积分服务 PointService:提供积分商城商品列表、详情、用户积分日志列表的组装与分页。
  • 后台积分控制器与模型:提供积分流水查询、筛选、删除、批量操作与参数设置入口。
  • 语言包 point.lang.php:定义积分相关文案与动作名称映射。

架构总览

积分系统的关键调用链包括:

  • 消费返积分:订单支付成功 → 状态机触发 → 计算积分 → 写入钱包 → 同步余额。
  • 积分兑换:用户选择积分抵扣 → 结账服务扣积分 → 继续下单流程。
  • 积分查询:小程序通过 API 获取积分商品列表与用户积分日志。
sequenceDiagram
participant C as "小程序客户端"
participant A as "API 积分控制器"
participant S as "前台积分服务"
participant W as "钱包服务"
participant O as "订单状态机"
participant K as "结账服务"
Note over C,A : 积分商城与积分记录查询
C->>A : 请求积分商品列表/用户积分日志
A->>S : 构建数据(分页/格式化)
S-->>A : 返回结果
A-->>C : 响应数据
Note over C,O : 消费返积分
C->>O : 订单支付完成回调
O->>W : createPoint(action=shopping, from=order_sn)
W-->>O : 成功/失败
O-->>C : 回调处理完成
Note over C,K : 积分抵扣下单
C->>K : 提交订单(mode=point)
K->>W : createPoint(action=exchange, -数量)
W-->>K : 成功/失败
K-->>C : 下单结果

详细组件分析

钱包服务 WalletService(积分写入与余额同步)

  • 职责:以事务和行锁方式写入积分流水,并同步用户余额快照,防止并发导致余额为负或重复扣减。
  • 关键点:
    • 读取最新 total 并加变动值,若结果为负则拒绝。
    • 支持多种 action(如 shopping、exchange、share 等)与来源 from(如 order_sn)。
    • 可记录 operator_type、operator_id、source_type、source_id、remark、ip 等审计字段。
flowchart TD
Start(["开始"]) --> CheckFeature["检查是否启用积分功能"]
CheckFeature --> |否| EndNo["返回 false"]
CheckFeature --> |是| ValidateUser["校验 user_id"]
ValidateUser --> |无效| EndNo
ValidateUser --> LockRow["对用户积分行加 FOR UPDATE 锁"]
LockRow --> CalcTotal["计算 new_total = total + point"]
CalcTotal --> CheckNegative{"new_total < 0 ?"}
CheckNegative --> |是| EndFail["返回 false"]
CheckNegative --> |否| WriteLog["写入积分流水"]
WriteLog --> SyncBalance["同步用户余额快照"]
SyncBalance --> EndOK["返回 true"]

订单状态机 OrderStatusTransition(消费返积分)

  • 职责:订单支付成功后,按金额比例计算积分并派发,同时去重避免重复发放。
  • 关键点:
    • 使用同一事务与订单行锁保护,防止并发重复发放。
    • 依据配置的比例参数计算积分,当积分为 0 则跳过。
    • 通过 action=shopping、from=order_sn 标识来源,便于追踪。
sequenceDiagram
participant OS as "订单状态机"
participant DB as "数据库"
participant W as "钱包服务"
OS->>DB : 开启事务 + 锁定订单行(FOR UPDATE)
OS->>DB : 检查该订单是否已发放过积分
alt 未发放且计算积分>0
OS->>W : createPoint(user_id, action=shopping, point, from=order_sn)
W-->>OS : 成功
else 已发放或积分为0
OS-->>OS : 跳过
end
OS->>DB : 提交事务

结账服务 CheckoutService(积分抵扣)

  • 职责:在 mode=point 时优先扣除积分,失败则回滚并清理购物车。
  • 关键点:
    • 使用事务包裹,确保积分扣减与后续下单步骤的一致性。
    • 失败时返回明确错误码与消息,便于前端提示。
sequenceDiagram
participant C as "客户端"
participant K as "结账服务"
participant W as "钱包服务"
C->>K : 提交订单(mode=point)
K->>K : 开启事务
K->>W : createPoint(user_id, action=exchange, -orderPoint, from=orderSn)
alt 扣积分成功
K-->>C : 继续下单流程
else 扣积分失败
K->>K : 回滚事务
K-->>C : 返回 point_not_enough
end

前台积分服务 PointService(积分商城与日志)

  • 职责:
    • 积分商城商品列表:按积分>0过滤、分页、格式化展示字段。
    • 积分商品详情:加载图片、模型列表、收藏状态等。
    • 用户积分日志:按用户过滤、排序、分页,并格式化动作名称。
classDiagram
class PointService {
+buildPointListData(page, pageUrl) array
+buildPointShowData(productId) array|false
+buildPointLogListData(userId, page, pageUrl) array
}
class Product {
+where() Builder
+applyDefaultOrder() Builder
+paginate(size, page, url) array
}
class PointLog {
+filterByUserId(userId) Builder
+applyDefaultOrder() Builder
+paginate(size, page, url) array
}
PointService --> Product : "查询积分商品"
PointService --> PointLog : "查询积分日志"

后台积分控制器与模型(流水管理与参数设置)

  • 职责:
    • 积分流水列表:支持按用户名、时间范围筛选与分页。
    • 批量操作:删除、批量动作等。
    • 参数设置:跳转至积分比例参数设置页。
  • 模型:
    • 提供 scope 筛选(user_id、时间范围)、默认排序、批量删除、分享奖励积分查询等。
flowchart TD
Req["后台请求"] --> Ctrl["PointController.index"]
Ctrl --> Svc["PointService.buildPointListData"]
Svc --> Model["Point.filterByUserId/filterByTimeStart/filterByTimeEnd"]
Model --> Page["分页与排序"]
Page --> View["渲染点.htm 视图"]

API 控制器(小程序端接口)

  • 积分商城控制器:返回商品列表、分页、总数,并为商品附加小程序链接。
  • 用户积分控制器:返回用户积分日志列表、总积分、分页。

依赖关系分析

  • 控制器到服务:API 与后台控制器均依赖各自的服务层进行业务编排。
  • 服务到模型:前台积分服务依赖产品模型与积分日志模型进行数据聚合。
  • 订单到钱包:订单状态机与结账服务依赖钱包服务进行积分写入。
  • 语言包:所有界面文案与动作名称统一从语言包获取,便于国际化。
graph LR
API_Point["API 积分控制器"] --> F_Svc["前台积分服务"]
API_User["API 用户积分控制器"] --> F_Svc
Admin_Point["后台积分控制器"] --> Admin_Model["后台积分模型"]
Order_Trans["订单状态机"] --> Wallet["钱包服务"]
Checkout["结账服务"] --> Wallet
F_Svc --> Product["产品模型"]
F_Svc --> PointLog["积分日志模型"]

性能与并发

  • 并发安全:钱包服务对积分行加 FOR UPDATE 锁,避免并发扣减导致的余额为负或重复发放。
  • 去重机制:订单状态机在发放积分前检查是否已发放过(基于 order_sn),结合行锁进一步保障一致性。
  • 分页与查询:前台积分服务使用分页减少数据传输量;后台积分列表支持多维度筛选提升检索效率。
  • 建议:
    • 在高并发场景下,确保数据库连接池与事务隔离级别合理配置。
    • 对高频查询(如积分日志)考虑缓存热点用户最近 N 条记录。
    • 对积分比例参数变更进行灰度发布与监控,避免大规模影响。

故障排查指南

  • 常见问题:
    • 积分余额不足:结账服务在积分抵扣失败时返回错误码与消息,需检查用户余额与扣减逻辑。
    • 重复发放:确认订单状态机是否正确检查已发放标记,以及行锁是否生效。
    • 余额为负:检查钱包服务的负数校验逻辑与并发锁是否正常工作。
  • 定位方法:
    • 查看积分日志:通过后台积分流水或小程序用户积分日志,核对 action、from、point、total。
    • 检查配置:确认 features.point 与 param.point_scale 等配置项是否启用与正确设置。
    • 日志与调试:关注钱包服务与订单状态机的异常日志,必要时增加更详细的上下文信息。

结论

DouPHP 积分系统通过钱包服务实现高并发安全的积分写入与余额同步,结合订单状态机与结账服务完成“消费返积分”与“积分抵扣”的核心闭环。前台与后台分别提供积分商城与流水管理能力,配合语言包实现多语言文案。建议在上线后持续监控积分发放与消耗情况,优化分页与缓存策略,提升整体性能与用户体验。

附录:配置与扩展建议

  • 配置项:
    • features.point:控制是否启用积分功能。
    • param.point_scale:消费返积分比例(每消费一定金额赠送的积分)。
    • pagination.point:积分商城商品列表分页大小。
  • 扩展方向:
    • 签到得积分:可在用户登录或签到流程中调用钱包服务写入 action=sign 的积分流水。
    • 分享奖励:在分享行为完成后,调用钱包服务写入 action=share 的积分流水。
    • 有效期管理:可在积分流水表中增加过期时间字段,并在结算时优先使用即将过期的积分。
    • 统计报表:基于积分日志表进行趋势分析、使用排行、兑换记录等维度统计。
添加日期:2026-10-05