refactor(utils): 修复密码哈希比较逻辑错误 feat(user): 新增按状态筛选优惠券接口 docs: 添加虚拟发货与任务中心相关文档 fix(wechat): 修正Code2Session上下文传递问题 test: 补充订单折扣与积分转换测试用例 build: 更新配置文件与构建脚本 style: 清理多余的空行与注释
6.7 KiB
6.7 KiB
约束与对齐
- 管理端仅支持“定时到具体时间点”的开奖,不支持设置“定时 N 分钟后开奖”。
- 计划包含:玩法策略、哈希可验证抽奖、退款+赠券流程、数据一致性、完整 API 与参数。
玩法与流程
- 一番赏
- 定时开奖:必填
scheduled_time(绝对时间戳) 与min_participants(最低人数)。到时若人数 < N:全额退款+赠券。≥N:统一开奖。 - 即时开奖:用户支付成功后立即抽奖并返回凭证。
- 定时开奖:必填
- 无限赏/对对碰/爬塔:标准抽奖流程(即时抽奖),策略差异体现在权重、过滤规则、后置效果。
抽奖与可验证性
- 种子:服务端使用加密安全
crypto/rand生成 32 字节seed,按期(issue)维度保存。 - 哈希签名:
signature = HMAC-SHA256(seed, user_id|issue_id|timestamp|nonce);nonce为 16 字节随机串,timestamp精确到毫秒。 - 客户端校验:本地按相同算法计算签名并比对;凭证包含必要输入。
数据模型(核心字段)
activities:id、name、play_type(ichiban/infinite/match/tower)、draw_mode(scheduled/instant)、min_participants、scheduled_time、refund_coupon_type、refund_coupon_amount、status(draft/active/closed)。issues:id、activity_id、seed、seed_version、original_qty、quantity、status(pending/drawing/done/failed)。rewards:id、issue_id、name、weight、original_qty、quantity、type、meta。draw_logs:id、issue_id、activity_id、user_id、reward_id、signature、timestamp、nonce、receipt_json。lottery_refund_logs:id、issue_id、order_id、user_id、amount、coupon_type、coupon_amount、reason、created_at、status(success/failed/retry)。
管理端 API 与参数
- 创建活动
POST /api/admin/lottery/activities- Body
{
"name": "一番赏·七月",
"play_type": "ichiban", // 枚举: ichiban | infinite | match | tower
"draw_mode": "scheduled", // 枚举: scheduled | instant
"min_participants": 100, // 定时玩法必填
"scheduled_time": "2025-12-05T20:00:00Z", // 绝对时间戳,禁止传相对分钟
"refund_coupon_type": "cash", // 枚举: cash | discount | gift
"refund_coupon_amount": 20.0, // 金额或面额
"description": "..."
}
- Response
{ "activity_id": 123 }
- 校验:当
draw_mode==scheduled时必须存在scheduled_time(>= 当前时间+最小提前量) 与min_participants;拒绝包含“分钟”相对参数。
- 更新活动
PATCH /api/admin/lottery/activities/:activity_id- Body(同创建,可部分字段)
- 禁止将
scheduled_time更新为相对分钟;仅允许更新为更晚的绝对时间。
- 创建活动期(含奖池与种子)
POST /api/admin/lottery/activities/:activity_id/issues- Body
{
"rewards": [
{ "name": "SSR皮肤", "weight": 1, "original_qty": 1, "type": "virtual", "meta": {"skin_id": 88} },
{ "name": "SR皮肤", "weight": 10, "original_qty": 50, "type": "virtual", "meta": {"skin_id": 77} }
]
}
- Response
{
"issue_id": 456,
"seed_version": 1
}
- 活动列表/详情
GET /api/admin/lottery/activities?play_type=&draw_mode=&status=&page=&size=GET /api/admin/lottery/activities/:activity_id
- 期列表/详情
GET /api/admin/lottery/activities/:activity_id/issues?page=&size=GET /api/admin/lottery/issues/:issue_id
- 手动关闭活动/期
POST /api/admin/lottery/activities/:activity_id/closePOST /api/admin/lottery/issues/:issue_id/close
APP 端 API 与参数
- 参与抽奖(创建订单/入场)
POST /api/app/lottery/join- Body
{
"activity_id": 123,
"issue_id": 456,
"channel": "wechat", // 支付渠道
"client_nonce": "base64..." // 可选,客户端随机串
}
- Response(即时模式可能包含抽奖结果;定时模式仅返回入场信息)
{
"join_id": "J202512030001",
"order_id": "O202512030009",
"pay_params": { /* JSAPI 等 */ },
"queued": true, // 定时玩法
"draw_mode": "scheduled"
}
- 即时抽奖(支付成功后自动触发,若需要主动查询)
GET /api/app/lottery/result?join_id=J202512030001- Response(包含可验证凭证)
{
"result": {
"reward_id": 789,
"reward_name": "SR皮肤"
},
"receipt": {
"issue_id": 456,
"seed_version": 1,
"timestamp": 1733251200123,
"nonce": "rB1A...==",
"signature": "hmacSha256Base64...",
"algorithm": "HMAC-SHA256",
"inputs": {
"user_id": 10086,
"issue_id": 456,
"timestamp": 1733251200123,
"nonce": "rB1A...=="
}
}
}
- 定时开奖结果查询(到点统一结算后)
GET /api/app/lottery/scheduled/result?issue_id=456&user_id=10086- Response 同上(若未达人数,返回退款与赠券信息)
{
"refunded": true,
"refund": { "order_id": "O202512030009", "amount": 29.9 },
"coupon": { "type": "cash", "amount": 20.0, "coupon_id": 33001 }
}
- 客户端校验助手(可选)
GET /api/app/lottery/issue/:issue_id/seed_version- Response
{ "seed_version": 1 }
支付/退款/赠券
- 支付回调:沿用
/api/pay/wechat_notify(落库订单状态,触发即时抽奖或定时入场)。 - 定时结算器:服务端按
scheduled_time扫描:- 人数 < N:批量退款,并为每位用户发放预设优惠券(
system_coupons)。 - 人数 ≥ N:统一抽奖与发放,写入
draw_logs与事务扣减奖励。
- 人数 < N:批量退款,并为每位用户发放预设优惠券(
- 退款接口(内部调用):对每个订单创建退款,记录
lottery_refund_logs并保证幂等。
一致性与异常处理
- 事务:入场/库存扣减/日志写入使用同一事务;失败回滚。
- 幂等:
join_id与order_id作为幂等键,退款/赠券均防重复。 - 定时任务:定期扫描 + 重试机制;失败写入日志,告警通知。
- 网络中断:客户端可凭
join_id查询结果;服务端保证结算原子性。
错误码(示例)
400:活动未开始/已结束/库存不足/限频/参数错误402:未支付409:重复参与/幂等冲突500:系统错误/结算失败(可重试)
测试与验收
- 单元:HMAC 随机选择、拒绝采样无偏、事务一致性、幂等与重试。
- 集成:支付→即时报奖→收据校验;定时人数不足→退款+送券。
- 文档:Swagger 补充所有请求/响应体;明确“禁止 N 分钟相对定时”,仅允许绝对时间戳。
交付清单
- 策略模块、管理端与 APP 端 API、哈希凭证、定时结算器、退款日志与发券流程、测试与文档。