# 优惠券功能实现进度 **需求文档**: [PRD-积分兑换洗车券功能.md](./PRD-积分兑换洗车券功能.md) **开始日期**: 2026-03-04 **当前版本**: v1.0(首期洗车券) --- ## 进度总览 | # | 子任务 | 状态 | 文件 | |---|--------|------|------| | 1 | Domain 实体类 | ✅ 完成 | `jsowell-pile/.../domain/` | | 2 | Mapper 接口和 XML | ✅ 完成 | `jsowell-pile/.../mapper/` + `resources/mapper/pile/` | | 3 | Service 层 | ✅ 完成 | `jsowell-pile/.../service/` | | 4 | 管理后台 Controller | ✅ 完成 | `jsowell-admin/.../web/controller/pile/` | | 5 | 用户端 API Controller | ✅ 完成 | `jsowell-admin/.../api/uniapp/customer/` | | 6 | Quartz 过期归档任务 | ✅ 完成 | `jsowell-quartz/.../task/JsowellTask.java`(方法 `expireCoupons`) | > 状态图例:⬜ 待开始 / 🔄 进行中 / ✅ 完成 --- ## Task 1:Domain 实体类 **状态**: ✅ 完成 ### 文件清单 | 文件 | 路径 | |------|------| | `CouponTemplate.java` | `jsowell-pile/src/main/java/com/jsowell/pile/domain/` | | `CouponTemplateScope.java` | `jsowell-pile/src/main/java/com/jsowell/pile/domain/` | | `MemberCoupon.java` | `jsowell-pile/src/main/java/com/jsowell/pile/domain/` | | `CouponVerifyRecord.java` | `jsowell-pile/src/main/java/com/jsowell/pile/domain/` | --- ## Task 2:Mapper 接口和 XML **状态**: ✅ 完成 ### 文件清单 | 文件 | 路径 | |------|------| | `CouponTemplateMapper.java` | `jsowell-pile/src/main/java/com/jsowell/pile/mapper/` | | `CouponTemplateScopeMapper.java` | `jsowell-pile/src/main/java/com/jsowell/pile/mapper/` | | `MemberCouponMapper.java` | `jsowell-pile/src/main/java/com/jsowell/pile/mapper/` | | `CouponVerifyRecordMapper.java` | `jsowell-pile/src/main/java/com/jsowell/pile/mapper/` | | `CouponTemplateMapper.xml` | `jsowell-pile/src/main/resources/mapper/pile/` | | `CouponTemplateScopeMapper.xml` | `jsowell-pile/src/main/resources/mapper/pile/` | | `MemberCouponMapper.xml` | `jsowell-pile/src/main/resources/mapper/pile/` | | `CouponVerifyRecordMapper.xml` | `jsowell-pile/src/main/resources/mapper/pile/` | --- ## Task 3:Service 层 **状态**: ✅ 完成 ### 文件清单 | 文件 | 路径 | |------|------| | `CouponTemplateService.java` | `jsowell-pile/src/main/java/com/jsowell/pile/service/` | | `CouponTemplateServiceImpl.java` | `jsowell-pile/src/main/java/com/jsowell/pile/service/impl/` | | `MemberCouponService.java` | `jsowell-pile/src/main/java/com/jsowell/pile/service/` | | `MemberCouponServiceImpl.java` | `jsowell-pile/src/main/java/com/jsowell/pile/service/impl/` | ### 核心方法 **CouponTemplateService** - `listForAdmin(CouponTemplate query, String merchantId)` - 后台列表(带权限过滤) - `add(CouponTemplate template, String loginMerchantId, boolean isPlatformAdmin)` - 新增(含 scope 校验) - `edit(CouponTemplate template, String loginMerchantId, boolean isPlatformAdmin)` - 编辑(含冻结字段校验) - `changeStatus(Long id, Integer status, String loginMerchantId)` - 上下架 **MemberCouponService** - `listAvailableTemplates(String memberId, Long stationId, int pageNum, int pageSize)` - 用户可兑换列表 - `exchange(String memberId, Long templateId, String requestId)` - 兑换(原子:扣积分+生成券) - `myList(String memberId, Integer status, int pageNum, int pageSize)` - 我的券包 - `detail(String memberId, String couponNo)` - 券详情 - `verify(String couponNo, Long storeId, String requestId, String operatorId)` - 核销 --- ## Task 4:管理后台 Controller **状态**: ✅ 完成 ### 文件清单 | 文件 | 路径 | |------|------| | `CouponTemplateController.java` | `jsowell-admin/src/main/java/com/jsowell/web/controller/pile/` | | `CouponRecordController.java` | `jsowell-admin/src/main/java/com/jsowell/web/controller/pile/` | --- ## Task 5:用户端 API Controller **状态**: ✅ 完成 ### 文件清单 | 文件 | 路径 | |------|------| | `CouponController.java` | `jsowell-admin/src/main/java/com/jsowell/api/uniapp/customer/` | --- ## Task 6:Quartz 过期归档任务 **状态**: ✅ 完成 方法 `expireCoupons()` 已合并到 `JsowellTask.java`,调用目标:`jsowellTask.expireCoupons()`,Cron:`0 5 0 * * ?` --- ## 关键设计决策 1. **兑换幂等**:`member_coupon.exchange_request_id` 唯一索引,捕获 `DuplicateKeyException` 返回已有结果 2. **库存扣减**:`UPDATE ... SET stock_remain=stock_remain-1 WHERE id=? AND (stock_remain>0 OR stock_remain=-1)` 3. **积分扣减**:复用现有 `MemberPointsInfoService.deductPoints()`,`type=3`(兑换消耗) 4. **scope 校验**:查询用户可见券时 JOIN `coupon_template_scope`,通过 `idx_scope_lookup` 索引反查 5. **过期判断**:查询侧用 `expire_time > NOW()` 动态判断,Quartz 仅做离线归档 6. **二维码安全**:券详情接口返回短时签名 token(HMAC-SHA256,5分钟有效),核销接口接受 token 或 couponNo 两种方式