SpecialPriceController.java 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package com.etotem.cfc.controller.special;
  2. import com.etotem.cfc.common.Result;
  3. import com.etotem.cfc.entity.SpecialPriceDeal;
  4. import com.etotem.cfc.service.SpecialPriceService;
  5. import com.etotem.cfc.util.ParamUtils;
  6. import org.springframework.web.bind.annotation.PostMapping;
  7. import org.springframework.web.bind.annotation.RequestBody;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import javax.annotation.Resource;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. /**
  14. * 限时特价(扫码闪购)小程序端接口。
  15. * 设计见 docs/superpowers/specs/2026-10-20-limited-time-special-price-design.md
  16. *
  17. * <p>注意:{@code /api/special-price/info} 处于白名单(免登录),{@code JwtInterceptor} 命中
  18. * PUBLIC_PATHS 后直接 return true,不写入任何 request attribute(连匿名 userId 也不写)。
  19. * 因此本控制器禁止使用 {@code @RequestAttribute("userId")},{@code userPurchased/userRemaining}
  20. * 恒为 0;每人限购由下单接口 {@code ProductOrderService.createSpecialDealOrder} 兜底校验。</p>
  21. */
  22. @RestController
  23. @RequestMapping("/api/special-price")
  24. public class SpecialPriceController {
  25. @Resource
  26. private SpecialPriceService specialPriceService;
  27. /**
  28. * 查询特价活动信息(公开)。
  29. * 请求体:{@code {dealId}}
  30. * 返回 data 字段:id, productId, name, specialPrice, startTime, endTime, runStatus,
  31. * totalQuantity, soldQuantity, remainingQuantity, perUserLimit, allowCoupon,
  32. * userPurchased, userRemaining。runStatus 严格取值
  33. * DRAFT/ACTIVE/NOT_STARTED/SOLD_OUT/ENDED/DISABLED/INVALID。
  34. */
  35. @PostMapping("/info")
  36. public Result<Map<String, Object>> info(@RequestBody Map<String, Object> params) {
  37. Long dealId = ParamUtils.getLong(params.get("dealId"));
  38. Map<String, Object> data = new HashMap<>();
  39. data.put("dealId", dealId);
  40. if (dealId == null) {
  41. data.put("runStatus", "INVALID");
  42. data.put("message", "活动不存在");
  43. return Result.success(data);
  44. }
  45. SpecialPriceDeal deal = specialPriceService.getById(dealId);
  46. if (deal == null) {
  47. data.put("runStatus", "INVALID");
  48. data.put("message", "活动不存在");
  49. return Result.success(data);
  50. }
  51. int total = deal.getTotalQuantity() != null ? deal.getTotalQuantity() : 0;
  52. int sold = deal.getSoldQuantity() != null ? deal.getSoldQuantity() : 0;
  53. String runStatus = SpecialPriceService.computeRunStatus(
  54. deal.getStatus(), deal.getStartTime(), deal.getEndTime(), sold, total);
  55. data.put("id", deal.getId());
  56. data.put("productId", deal.getProductId());
  57. data.put("name", deal.getName());
  58. data.put("specialPrice", deal.getSpecialPrice());
  59. data.put("startTime", deal.getStartTime());
  60. data.put("endTime", deal.getEndTime());
  61. data.put("runStatus", runStatus);
  62. data.put("totalQuantity", total);
  63. data.put("soldQuantity", sold);
  64. data.put("remainingQuantity", Math.max(total - sold, 0));
  65. data.put("perUserLimit", deal.getPerUserLimit() != null ? deal.getPerUserLimit() : 1);
  66. data.put("allowCoupon", deal.getAllowCoupon() != null ? deal.getAllowCoupon() : 0);
  67. // 白名单路径不注入用户属性:恒为 0,每人限购由下单接口兜底校验
  68. data.put("userPurchased", 0);
  69. data.put("userRemaining", 0);
  70. return Result.success(data);
  71. }
  72. }