diff --git a/docs/coupon-impl-progress.md b/docs/coupon-impl-progress.md index fef70309c..ff19a995e 100644 --- a/docs/coupon-impl-progress.md +++ b/docs/coupon-impl-progress.md @@ -118,7 +118,14 @@ --- -## 关键设计决策 +## 前端页面 + +| # | 子任务 | 状态 | 文件 | +|---|--------|------|------| +| F1 | API 文件 | ✅ 完成 | `jsowell-charge-ui/src/api/coupon/template.js` / `record.js` | +| F2 | 券模板管理页 | ✅ 完成 | `jsowell-charge-ui/src/views/coupon/template/index.vue` | +| F3 | 兑换记录页 | ✅ 完成 | `jsowell-charge-ui/src/views/coupon/record/index.vue` | +| F4 | 路由注册 | ✅ 完成 | `jsowell-charge-ui/src/router/index.js` | 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)` diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/CouponTemplateServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/CouponTemplateServiceImpl.java index f9dca3c1c..93403fab3 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/CouponTemplateServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/CouponTemplateServiceImpl.java @@ -74,7 +74,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { public void edit(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) { CouponTemplate existing = couponTemplateMapper.selectById(template.getId()); if (existing == null) { - throw new BusinessException("券模板不存在"); + throw new BusinessException("ERROR", "券模板不存在"); } checkOwnership(existing, loginMerchantId, isPlatformAdmin); @@ -83,7 +83,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { if (hasExchanged) { if (template.getType() != null || template.getPointsCost() != null || template.getValidityType() != null || template.getValidDays() != null) { - throw new BusinessException("该券已有用户兑换,不可修改券类型、积分价格、有效期规则等核心字段"); + throw new BusinessException("ERROR", "该券已有用户兑换,不可修改券类型、积分价格、有效期规则等核心字段"); } } @@ -102,7 +102,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { public void changeStatus(Long id, Integer status, Long loginMerchantId, boolean isPlatformAdmin) { CouponTemplate existing = couponTemplateMapper.selectById(id); if (existing == null) { - throw new BusinessException("券模板不存在"); + throw new BusinessException("ERROR", "券模板不存在"); } checkOwnership(existing, loginMerchantId, isPlatformAdmin); @@ -124,7 +124,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { } // 运营商管理员不能选全平台 if (!isPlatformAdmin && scopeType == 1) { - throw new BusinessException("运营商管理员不能创建全平台范围的券"); + throw new BusinessException("ERROR", "运营商管理员不能创建全平台范围的券"); } // 运营商管理员选指定站点时,校验站点归属 if (!isPlatformAdmin && scopeType == 3 && !CollectionUtils.isEmpty(template.getScopeList())) { @@ -142,7 +142,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { private void checkOwnership(CouponTemplate template, Long loginMerchantId, boolean isPlatformAdmin) { if (!isPlatformAdmin) { if (!loginMerchantId.equals(template.getCreatorMerchantId())) { - throw new BusinessException("无权操作该券模板"); + throw new BusinessException("ERROR", "无权操作该券模板"); } } } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberCouponServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberCouponServiceImpl.java index 8c34566fa..156a5a080 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberCouponServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberCouponServiceImpl.java @@ -81,24 +81,24 @@ public class MemberCouponServiceImpl implements MemberCouponService { public MemberCoupon exchange(String memberId, Long templateId, String requestId) { CouponTemplate template = couponTemplateMapper.selectById(templateId); if (template == null || template.getStatus() != 1) { - throw new BusinessException("券模板不存在或已下架"); + throw new BusinessException("ERROR", "券模板不存在或已下架"); } Date now = new Date(); // 1. 兑换时间段校验 if (template.getExchangeStartTime() != null && now.before(template.getExchangeStartTime())) { - throw new BusinessException("兑换活动尚未开始"); + throw new BusinessException("ERROR", "兑换活动尚未开始"); } if (template.getExchangeEndTime() != null && now.after(template.getExchangeEndTime())) { - throw new BusinessException("兑换活动已结束"); + throw new BusinessException("ERROR", "兑换活动已结束"); } // 2. 单用户累计限额 if (template.getTotalLimit() != null && template.getTotalLimit() > 0) { int total = memberCouponMapper.countByMemberAndTemplate(memberId, templateId); if (total >= template.getTotalLimit()) { - throw new BusinessException("您已达到兑换上限"); + throw new BusinessException("ERROR", "您已达到兑换上限"); } } @@ -107,7 +107,7 @@ public class MemberCouponServiceImpl implements MemberCouponService { Date[] monthRange = getMonthRange(now); int monthly = memberCouponMapper.countMonthByMemberAndTemplate(memberId, templateId, monthRange[0], monthRange[1]); if (monthly >= template.getMonthlyLimit()) { - throw new BusinessException("本月兑换已达上限"); + throw new BusinessException("ERROR", "本月兑换已达上限"); } } @@ -116,7 +116,7 @@ public class MemberCouponServiceImpl implements MemberCouponService { Date[] dayRange = getDayRange(now); int daily = memberCouponMapper.countTodayByMemberAndTemplate(memberId, templateId, dayRange[0], dayRange[1]); if (daily >= template.getDailyLimit()) { - throw new BusinessException("今日兑换已达上限"); + throw new BusinessException("ERROR", "今日兑换已达上限"); } } @@ -124,7 +124,7 @@ public class MemberCouponServiceImpl implements MemberCouponService { if (template.getStockRemain() != null && template.getStockRemain() != -1) { int updated = couponTemplateMapper.deductStock(templateId); if (updated <= 0) { - throw new BusinessException("库存不足,兑换失败"); + throw new BusinessException("ERROR", "库存不足,兑换失败"); } } @@ -158,7 +158,7 @@ public class MemberCouponServiceImpl implements MemberCouponService { .filter(c -> requestId.equals(c.getExchangeRequestId())) .map(MemberCoupon::getCouponNo) .findFirst() - .orElseThrow(() -> new BusinessException("兑换异常,请重试"))); + .orElseThrow(() -> new BusinessException("ERROR", "兑换异常,请重试"))); } return coupon; } @@ -172,7 +172,7 @@ public class MemberCouponServiceImpl implements MemberCouponService { public MemberCoupon detail(String memberId, String couponNo) { MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo); if (coupon == null || !memberId.equals(coupon.getMemberId())) { - throw new BusinessException("券不存在"); + throw new BusinessException("ERROR", "券不存在"); } return coupon; } @@ -191,14 +191,14 @@ public class MemberCouponServiceImpl implements MemberCouponService { if (existing.getResult() == 1) { return; // 已成功核销,幂等返回 } - throw new BusinessException("该核销请求已失败,请重新发起"); + throw new BusinessException("ERROR", "该核销请求已失败,请重新发起"); } } MemberCoupon coupon = memberCouponMapper.selectByCouponNo(couponNo); if (coupon == null) { writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "券不存在"); - throw new BusinessException("券不存在"); + throw new BusinessException("ERROR", "券不存在"); } // 校验 scope:核销门店是否在券可用范围内 @@ -206,7 +206,7 @@ public class MemberCouponServiceImpl implements MemberCouponService { if (template != null && template.getScopeType() != null && template.getScopeType() > 1) { if (!isScopeMatch(template, storeId)) { writeVerifyLog(couponNo, requestId, storeId, operatorId, 2, "核销门店不在券可用范围内"); - throw new BusinessException("核销门店不在券可用范围内"); + throw new BusinessException("ERROR", "核销门店不在券可用范围内"); } }