diff --git a/mobile-web/src/api/promotion.js b/mobile-web/src/api/promotion.js
index 4b74b1b7a..37a96ff50 100644
--- a/mobile-web/src/api/promotion.js
+++ b/mobile-web/src/api/promotion.js
@@ -20,4 +20,24 @@ export function getProductRecommendList() {
// Coupon Template
+export function getCouponTemplate(id) {
+ return request({
+ url: '/promotion-api/users/coupon/template/get',
+ method: 'get',
+ params: {
+ id,
+ }
+ });
+}
+
+export function doAddCouponCard(templateId) {
+ return request({
+ url: '/promotion-api/users/coupon/card/add',
+ method: 'post',
+ params: {
+ templateId,
+ }
+ });
+}
+
// Coupon Card
diff --git a/mobile-web/src/api/user.js b/mobile-web/src/api/user.js
index d0f768ddf..f9c7ec30e 100644
--- a/mobile-web/src/api/user.js
+++ b/mobile-web/src/api/user.js
@@ -81,7 +81,7 @@ export function getUserInfo() {
export function doUserUpdateNickname(nickname) {
return request({
- url: 'user-api/users/user/update_nickname',
+ url: '/user-api/users/user/update_nickname',
method: 'post',
params: {
nickname,
@@ -91,7 +91,7 @@ export function doUserUpdateNickname(nickname) {
export function doPassportMobileRegister(mobile, code) {
return request({
- url: 'user-api/users/passport/mobile/register',
+ url: '/user-api/users/passport/mobile/register',
method: 'post',
params: {
mobile,
@@ -102,7 +102,7 @@ export function doPassportMobileRegister(mobile, code) {
export function doPassportMobileSendRegisterCode(mobile) {
return request({
- url: 'user-api/users/passport/mobile/send_register_code',
+ url: '/user-api/users/passport/mobile/send_register_code',
method: 'post',
params: {
mobile,
diff --git a/mobile-web/src/page/coupon/fetch.vue b/mobile-web/src/page/coupon/fetch.vue
index 03165896a..ceff598e7 100644
--- a/mobile-web/src/page/coupon/fetch.vue
+++ b/mobile-web/src/page/coupon/fetch.vue
@@ -1,9 +1,54 @@
-
-
-
-
+
+
+
+
+
+ 领取优惠劵
+
diff --git a/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/config/MVCConfiguration.java b/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/config/MVCConfiguration.java
index 6474ea705..b7ee655c4 100644
--- a/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/config/MVCConfiguration.java
+++ b/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/config/MVCConfiguration.java
@@ -2,6 +2,11 @@ package cn.iocoder.mall.promotion.application.config;
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
import cn.iocoder.common.framework.servlet.CorsFilter;
+import cn.iocoder.mall.admin.sdk.interceptor.AdminAccessLogInterceptor;
+import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
+import cn.iocoder.mall.user.sdk.interceptor.UserAccessLogInterceptor;
+import cn.iocoder.mall.user.sdk.interceptor.UserSecurityInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -14,23 +19,31 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableWebMvc
@Configuration
@Import(value = {GlobalExceptionHandler.class, // 统一全局返回
-// AdminSecurityInterceptor.class
+ AdminSecurityInterceptor.class, UserAccessLogInterceptor.class,
+ UserSecurityInterceptor.class, AdminAccessLogInterceptor.class,
})
public class MVCConfiguration implements WebMvcConfigurer {
// @Autowired
// private UserSecurityInterceptor securityInterceptor;
-// @Autowired
-// private AdminSecurityInterceptor adminSecurityInterceptor;
-// @Autowired
-// private AdminAccessLogInterceptor adminAccessLogInterceptor;
+ @Autowired
+ private UserSecurityInterceptor userSecurityInterceptor;
+ @Autowired
+ private UserAccessLogInterceptor userAccessLogInterceptor;
+ @Autowired
+ private AdminSecurityInterceptor adminSecurityInterceptor;
+ @Autowired
+ private AdminAccessLogInterceptor adminAccessLogInterceptor;
//
@Override
public void addInterceptors(InterceptorRegistry registry) {
-// registry.addInterceptor(securityInterceptor).addPathPatterns("/user/**", "/admin/**"); // 只拦截我们定义的接口
-// registry.addInterceptor(adminAccessLogInterceptor).addPathPatterns("/admins/**");
-// registry.addInterceptor(adminSecurityInterceptor).addPathPatterns("/admins/**");
+ // 用户
+ registry.addInterceptor(userAccessLogInterceptor).addPathPatterns("/users/**");
+ registry.addInterceptor(userSecurityInterceptor).addPathPatterns("/users/**"); // 只拦截我们定义的接口
+ // 管理员
+ registry.addInterceptor(adminAccessLogInterceptor).addPathPatterns("/admins/**");
+ registry.addInterceptor(adminSecurityInterceptor).addPathPatterns("/admins/**");
}
@Override
@@ -48,4 +61,4 @@ public class MVCConfiguration implements WebMvcConfigurer {
return registrationBean;
}
-}
\ No newline at end of file
+}
diff --git a/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/controller/users/UsersCouponController.java b/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/controller/users/UsersCouponController.java
index 4dc623315..fcf5eb157 100644
--- a/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/controller/users/UsersCouponController.java
+++ b/promotion/promotion-application/src/main/java/cn/iocoder/mall/promotion/application/controller/users/UsersCouponController.java
@@ -8,18 +8,16 @@ import cn.iocoder.mall.promotion.application.convert.CouponCardConvert;
import cn.iocoder.mall.promotion.application.convert.CouponTemplateConvert;
import cn.iocoder.mall.promotion.application.vo.users.UsersCouponCardVO;
import cn.iocoder.mall.promotion.application.vo.users.UsersCouponTemplateVO;
+import cn.iocoder.mall.user.sdk.annotation.PermitAll;
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
import com.alibaba.dubbo.config.annotation.Reference;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
@RestController
-@RequestMapping("admins/coupon")
+@RequestMapping("users/coupon")
@Api("优惠劵(码)模块")
public class UsersCouponController {
@@ -31,6 +29,7 @@ public class UsersCouponController {
@GetMapping("/template/get")
@ApiOperation(value = "优惠劵(码)模板信息")
@ApiImplicitParam(name = "id", value = "优惠劵(码)模板编号", required = true, example = "10")
+ @PermitAll
public CommonResult templateGet(@RequestParam("id") Integer id) {
CouponTemplateBO template = couponService.getCouponTemplate(id).getData();
return CommonResult.success(CouponTemplateConvert.INSTANCE.convert2(template));
@@ -38,7 +37,7 @@ public class UsersCouponController {
// ========== 优惠劵 ==========
- @GetMapping("/card/add")
+ @PostMapping("/card/add")
@ApiOperation(value = "领取优惠劵")
@ApiImplicitParam(name = "templateId", value = "优惠劵(码)模板编号", required = true, example = "10")
public CommonResult cardAdd(@RequestParam("templateId") Integer templateId) {
diff --git a/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/PromotionErrorCodeEnum.java b/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/PromotionErrorCodeEnum.java
index 999b663f2..af574195b 100644
--- a/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/PromotionErrorCodeEnum.java
+++ b/promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/constant/PromotionErrorCodeEnum.java
@@ -22,7 +22,8 @@ public enum PromotionErrorCodeEnum {
PRODUCT_TEMPLATE_NOT_CODE(1006002002, "不是优惠码模板"),
PRODUCT_TEMPLATE_TOTAL_CAN_NOT_REDUCE(1006002003, "优惠劵(码)模板的发放数量不能减小"),
PRODUCT_TEMPLATE_STATUS_NOT_ENABLE(1006002004, "优惠劵模板(码)未开启"),
-
+ PRODUCT_TEMPLATE_TOTAL_NOT_ENOUGH(1006002005, "优惠劵(码)模板的发放量不足"),
+ PRODUCT_TEMPLATE_CARD_ADD_EXCEED_QUOTA(1006002006, "优惠劵领取到达上限"),
;
private final int code;
diff --git a/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponCardMapper.java b/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponCardMapper.java
index 8560c2e7c..78df37962 100644
--- a/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponCardMapper.java
+++ b/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponCardMapper.java
@@ -15,6 +15,9 @@ public interface CouponCardMapper {
Integer selectCountByPage(@Param("status") Integer status);
+ int selectCountByUserIdAndTemplateId(@Param("userId") Integer userId,
+ @Param("templateId") Integer templateId);
+
void insert(CouponCardDO couponCardDO);
int update(CouponCardDO couponCardDO);
diff --git a/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponTemplateMapper.java b/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponTemplateMapper.java
index 7bf2f1639..23195949c 100644
--- a/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponTemplateMapper.java
+++ b/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/dao/CouponTemplateMapper.java
@@ -27,4 +27,6 @@ public interface CouponTemplateMapper {
int update(CouponTemplateDO couponTemplate);
+ int updateStatFetchNumIncr(@Param("id") Integer id);
+
}
diff --git a/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/service/CouponServiceImpl.java b/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/service/CouponServiceImpl.java
index 5cd78f229..490057175 100644
--- a/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/service/CouponServiceImpl.java
+++ b/promotion/promotion-service-impl/src/main/java/cn/iocoder/mall/promotion/biz/service/CouponServiceImpl.java
@@ -19,6 +19,7 @@ import cn.iocoder.mall.promotion.biz.dataobject.CouponCardDO;
import cn.iocoder.mall.promotion.biz.dataobject.CouponTemplateDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Date;
@@ -176,6 +177,7 @@ public class CouponServiceImpl implements CouponService {
// ========== 优惠劵 ==========
@Override
+ @Transactional
public CommonResult addCouponCard(Integer userId, Integer couponTemplateId) {
// 校验 CouponCardTemplate 存在
CouponTemplateDO template = couponTemplateMapper.selectById(couponTemplateId);
@@ -190,6 +192,19 @@ public class CouponServiceImpl implements CouponService {
if (!CouponTemplateStatusEnum.ENABLE.getValue().equals(template.getStatus())) {
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_STATUS_NOT_ENABLE.getCode());
}
+ // 校验 CouponCardTemplate 是否到达可领取的上限
+ if (template.getStatFetchNum() > template.getTotal()) {
+ return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_TOTAL_NOT_ENOUGH.getCode());
+ }
+ // 校验单人可领取优惠劵是否到达上限
+ if (couponCardMapper.selectCountByUserIdAndTemplateId(userId, couponTemplateId) > template.getQuota()) {
+ return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
+ }
+ // 增加优惠劵已领取量
+ int updateTemplateCount = couponTemplateMapper.updateStatFetchNumIncr(couponTemplateId);
+ if (updateTemplateCount == 0) { // 超过 CouponCardTemplate 发放量
+ return ServiceExceptionUtil.error(PromotionErrorCodeEnum.PRODUCT_TEMPLATE_CARD_ADD_EXCEED_QUOTA.getCode());
+ }
// 创建优惠劵
// 1. 基本信息 + 领取情况
CouponCardDO card = new CouponCardDO()
diff --git a/promotion/promotion-service-impl/src/main/resources/mapper/CouponCardMapper.xml b/promotion/promotion-service-impl/src/main/resources/mapper/CouponCardMapper.xml
index 1082ebe80..670822568 100644
--- a/promotion/promotion-service-impl/src/main/resources/mapper/CouponCardMapper.xml
+++ b/promotion/promotion-service-impl/src/main/resources/mapper/CouponCardMapper.xml
@@ -56,6 +56,20 @@
+
+
INSERT INTO coupon_card (
template_id, status, user_id, take_type,
diff --git a/promotion/promotion-service-impl/src/main/resources/mapper/CouponTemplateMapper.xml b/promotion/promotion-service-impl/src/main/resources/mapper/CouponTemplateMapper.xml
index 8a4938ded..3f323a821 100644
--- a/promotion/promotion-service-impl/src/main/resources/mapper/CouponTemplateMapper.xml
+++ b/promotion/promotion-service-impl/src/main/resources/mapper/CouponTemplateMapper.xml
@@ -149,4 +149,11 @@
WHERE id = #{id}
+
+ UPDATE coupon_template
+ SET stat_fetch_Num = stat_fetch_Num + 1
+ WHERE id = #{id}
+ AND total > stat_fetch_Num
+
+
diff --git a/user/user-application/src/main/java/cn/iocoder/mall/user/application/config/MVCConfiguration.java b/user/user-application/src/main/java/cn/iocoder/mall/user/application/config/MVCConfiguration.java
index 6ac5b0a5c..ac6ff8cbc 100644
--- a/user/user-application/src/main/java/cn/iocoder/mall/user/application/config/MVCConfiguration.java
+++ b/user/user-application/src/main/java/cn/iocoder/mall/user/application/config/MVCConfiguration.java
@@ -49,4 +49,4 @@ public class MVCConfiguration implements WebMvcConfigurer {
return registrationBean;
}
-}
\ No newline at end of file
+}
diff --git a/user/user-service-api/src/main/java/cn/iocoder/mall/user/api/dto/UserAccessLogAddDTO.java b/user/user-service-api/src/main/java/cn/iocoder/mall/user/api/dto/UserAccessLogAddDTO.java
index 1b50edb8a..015ce0d01 100644
--- a/user/user-service-api/src/main/java/cn/iocoder/mall/user/api/dto/UserAccessLogAddDTO.java
+++ b/user/user-service-api/src/main/java/cn/iocoder/mall/user/api/dto/UserAccessLogAddDTO.java
@@ -4,6 +4,7 @@ import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
+import java.io.Serializable;
import java.util.Date;
/**
@@ -11,7 +12,7 @@ import java.util.Date;
*/
@Data
@Accessors(chain = true)
-public class UserAccessLogAddDTO {
+public class UserAccessLogAddDTO implements Serializable {
/**
* 用户编号 - 空