|
|
@@ -1782,3 +1782,58 @@ Web 管理端定义活动海报模板(迁移381 `activity_poster_templates`
|
|
|
**新增表:** `fat_weight_record`、`fat_diet_record`、`fat_exercise_record`、`fat_goal`(迁移 355–358,DatabaseInitializer)
|
|
|
|
|
|
*文档更新:2026-10-09(减脂专题新增)*
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 4.53 限时特价(扫码闪购)
|
|
|
+
|
|
|
+> 设计规格:`specs/2026-10-20-limited-time-special-price-design.md`;
|
|
|
+> 新建 `special_price_deals` 表(迁移 389)+ `product_orders.special_deal_id` 列(迁移 390)。
|
|
|
+
|
|
|
+**用户端(公开接口,无需登录)**
|
|
|
+
|
|
|
+| 路径 | 说明 |
|
|
|
+|---|---|
|
|
|
+| `POST /api/special-price/info` | 查询活动详情(白名单,JwtInterceptor 公开路径;`userPurchased`/`userRemaining` 恒 0,每人限购由下单接口兜底) |
|
|
|
+
|
|
|
+请求体:`{ "dealId": 1 }`
|
|
|
+响应 `data` 字段:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "id": 1, "productId": 10, "productName": "示例商品",
|
|
|
+ "name": "开售闪购", "specialPrice": 500, "productPrice": 990,
|
|
|
+ "startTime": "2026-10-20 12:00:00", "endTime": "2026-10-21 12:00:00",
|
|
|
+ "totalQuantity": 100, "soldQuantity": 23, "remainingQuantity": 77,
|
|
|
+ "perUserLimit": 2, "allowCoupon": 0, "runStatus": "ACTIVE",
|
|
|
+ "userPurchased": 0, "userRemaining": 0
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+`runStatus` 枚举:`ACTIVE`(进行中)/`NOT_STARTED`(未开始)/`SOLD_OUT`(已售罄)/`ENDED`(已结束)/`DISABLED`(已停用)/`DRAFT`(草稿)/`INVALID`(活动不存在)。白名单路径不写 request attribute,每人限购由下单接口最终校验。
|
|
|
+
|
|
|
+**下单(特价路径)**
|
|
|
+
|
|
|
+`POST /api/product/order/create` 请求体新增 `specialDealId`(Long,可选)。若 `specialDealId != null` 走特价下单分支:
|
|
|
+
|
|
|
+1. 校验活动存在、`status=active`、`NOW() ∈ [start_time, end_time]`、商品一致
|
|
|
+2. 每人限购校验(`countByDeal` 累计 < `perUserLimit`)
|
|
|
+3. `allowCoupon=0` 且 `couponId` 非空 → 拒绝
|
|
|
+4. 原子扣量 `consumeQuota(id, qty)`(失败按 runStatus 返回明确原因)
|
|
|
+5. `insert` 订单行 `special_deal_id = dealId`,`unit_price = specialPrice`
|
|
|
+6. 回滚挂载点:`cancel`(用户取消)、`approveRefund`(退款完成)、`OrderTimeoutCancelTask`(超时取消),三处调用 `releaseQuota`(`GREATEST(sold_quantity - qty, 0)` 防负)
|
|
|
+
|
|
|
+**供应商改价拒绝**:`reviewUpdate` 开头若 `order.specialDealId != null` 直接 `Result.error("特价订单不允许修改价格")`。
|
|
|
+
|
|
|
+**管理端(admin 角色)**
|
|
|
+
|
|
|
+| 路径 | 权限 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `POST /api/admin/special-price/list` | admin | 分页列表(body: `{page,size,keyword,runStatus}`;`runStatus` 可传 `ACTIVE/NOT_STARTED/SOLD_OUT/ENDED` 或 `draft/disabled`,空=全部;响应 `data.records[]` + `data.total`) |
|
|
|
+| `POST /api/admin/special-price/create` | admin | 新建(body: `{productId,name,specialPrice,startTime,endTime,totalQuantity,perUserLimit,allowCoupon}`;`specialPrice`/`productPrice`/`totalQuantity` 单位均为分;同商品互斥 active) |
|
|
|
+| `POST /api/admin/special-price/update` | admin | 修改(body 同 create + `id`;仅 `draft/disabled` 可修改) |
|
|
|
+| `POST /api/admin/special-price/status` | admin | 启停(body: `{id, action}`;`action ∈ {enable, disable}`;启用时再次校验互斥) |
|
|
|
+| `POST /api/admin/special-price/delete` | admin | 删除(body: `{id}`;已有特价订单时拒绝) |
|
|
|
+| `POST /api/admin/special-price/qrcode` | admin | 生成小程序码(body: `{id}`;`scene=id={productId}&sp={dealId}`,落地页 `product-detail`;返回 `data:{qrCodeBase64, scene, note?}`;测试模式 note 提示无法生成真实码) |
|
|
|
+
|
|
|
+*文档更新:2026-10-20(限时特价/扫码闪购新增)*
|