Переглянути джерело

feat(coupon): 新增小程序优惠券功能及相关接口

- 新增 AppCouponQuery 查询对象,支持用户 ID 和优惠券状态查询
- 新增 AppCouponStatusNumVO 响应对象,用于返回各类优惠券数量统计
- 修改首页 Banner 接口,增加 location 参数以区分展示位置
- 在 BannerInfo 实体及表单中新增 location 字段,表示展示位置(1-首页,2-个人中心)
- 扩展 CouponMapper 和 XML 文件,新增用户优惠券分页查询和状态统计方法
- 在 CouponService 中新增 getUserCouponPage 和 getCouponStatusNum 方法
- 实现优惠券模板编码自动生成逻辑,并完善相关查询条件支持
- 调整控制器层接口,增加个人优惠券列表、数量统计和待领取优惠券接口
- 优化 CouponTemplateQuery 查询参数,补充名称、状态、类型等过滤条件
- 移除 CouponTemplateForm 中对 id 的非空校验限制
wzq 1 день тому
батько
коміт
3628251812
18 змінених файлів з 231 додано та 26 видалено
  1. 3 3
      src/main/java/com/zsElectric/boot/business/controller/applet/AppletHomeController.java
  2. 39 0
      src/main/java/com/zsElectric/boot/business/controller/applet/AppletUserController.java
  3. 7 1
      src/main/java/com/zsElectric/boot/business/mapper/CouponMapper.java
  4. 2 1
      src/main/java/com/zsElectric/boot/business/mapper/CouponTemplateMapper.java
  5. 4 0
      src/main/java/com/zsElectric/boot/business/model/entity/BannerInfo.java
  6. 3 0
      src/main/java/com/zsElectric/boot/business/model/form/BannerInfoForm.java
  7. 0 1
      src/main/java/com/zsElectric/boot/business/model/form/CouponTemplateForm.java
  8. 14 0
      src/main/java/com/zsElectric/boot/business/model/query/CouponTemplateQuery.java
  9. 25 0
      src/main/java/com/zsElectric/boot/business/model/query/applet/AppCouponQuery.java
  10. 2 0
      src/main/java/com/zsElectric/boot/business/model/vo/BannerInfoVO.java
  11. 26 0
      src/main/java/com/zsElectric/boot/business/model/vo/applet/AppCouponStatusNumVO.java
  12. 1 1
      src/main/java/com/zsElectric/boot/business/service/AppletHomeService.java
  13. 5 0
      src/main/java/com/zsElectric/boot/business/service/CouponService.java
  14. 2 1
      src/main/java/com/zsElectric/boot/business/service/impl/AppletHomeServiceImpl.java
  15. 18 0
      src/main/java/com/zsElectric/boot/business/service/impl/CouponServiceImpl.java
  16. 19 0
      src/main/java/com/zsElectric/boot/business/service/impl/CouponTemplateServiceImpl.java
  17. 58 18
      src/main/resources/mapper/business/CouponMapper.xml
  18. 3 0
      src/main/resources/mapper/business/CouponTemplateMapper.xml

+ 3 - 3
src/main/java/com/zsElectric/boot/business/controller/applet/AppletHomeController.java

@@ -58,8 +58,8 @@ public class AppletHomeController {
      * @return Banner列表
      */
     @Operation(summary = "获取首页Banner列表")
-    @GetMapping("/getBannerList")
-    public Result<List<BannerInfoVO>> getBannerList() {
-        return Result.success(appletHomeService.getBannerList());
+    @GetMapping("/getBannerList/{location}")
+    public Result<List<BannerInfoVO>> getBannerList(@PathVariable("location") Integer location) {
+        return Result.success(appletHomeService.getBannerList(location));
     }
 }

+ 39 - 0
src/main/java/com/zsElectric/boot/business/controller/applet/AppletUserController.java

@@ -1,19 +1,31 @@
 package com.zsElectric.boot.business.controller.applet;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.zsElectric.boot.business.model.entity.UserFeedback;
 import com.zsElectric.boot.business.model.form.UserFeedbackForm;
 import com.zsElectric.boot.business.model.form.applet.AppFeedbackForm;
+import com.zsElectric.boot.business.model.query.CouponQuery;
+import com.zsElectric.boot.business.model.query.CouponTemplateQuery;
+import com.zsElectric.boot.business.model.query.applet.AppCouponQuery;
 import com.zsElectric.boot.business.model.query.applet.AppUserOrderInfoQuery;
+import com.zsElectric.boot.business.model.vo.CouponTemplateVO;
+import com.zsElectric.boot.business.model.vo.CouponVO;
+import com.zsElectric.boot.business.model.vo.applet.AppCouponStatusNumVO;
 import com.zsElectric.boot.business.model.vo.applet.AppletUserInfoVO;
+import com.zsElectric.boot.business.service.CouponService;
+import com.zsElectric.boot.business.service.CouponTemplateService;
 import com.zsElectric.boot.business.service.UserFeedbackService;
 import com.zsElectric.boot.business.service.UserInfoService;
+import com.zsElectric.boot.common.constant.SystemConstants;
+import com.zsElectric.boot.core.web.PageResult;
 import com.zsElectric.boot.core.web.Result;
 import com.zsElectric.boot.security.util.SecurityUtils;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -28,6 +40,10 @@ public class AppletUserController {
 
     private final UserFeedbackService userFeedbackService;
 
+    private final CouponService couponService;
+
+    private final CouponTemplateService couponTemplateService;
+
     @Operation(summary = "微信小程序获取当前登录信息")
     @GetMapping("/getUserInfo")
     public Result<AppletUserInfoVO> getUserInfo() {
@@ -54,4 +70,27 @@ public class AppletUserController {
         List<UserFeedback> list = userFeedbackService.list(Wrappers.<UserFeedback>lambdaQuery().eq(UserFeedback::getUserId, SecurityUtils.getUserId()));
         return Result.success(list);
     }
+
+    @Operation(summary = "个人优惠券列表")
+    @PostMapping("/getCouponPage")
+    public Result<IPage<CouponVO>> getCouponPage(@RequestBody AppCouponQuery queryParams) {
+        IPage<CouponVO> result = couponService.getUserCouponPage(queryParams);
+        return Result.success(result);
+    }
+
+    @Operation(summary = "获取个人优惠券数量")
+    @GetMapping("/getCouponStatusNum")
+    public Result<AppCouponStatusNumVO> getCouponStatusNum() {
+        AppCouponStatusNumVO result = couponService.getCouponStatusNum(SecurityUtils.getUserId());
+        return Result.success(result);
+    }
+
+    @Operation(summary = "待领取优惠券列表")
+    @GetMapping("/getCouponTemplatePage")
+    public Result<IPage<CouponTemplateVO>> getAppCouponTemplatePage() {
+        CouponTemplateQuery CouponTemplateQuery = new CouponTemplateQuery();
+        CouponTemplateQuery.setStatus(SystemConstants.STATUS_ONE);
+        IPage<CouponTemplateVO> result = couponTemplateService.getCouponTemplatePage(CouponTemplateQuery);
+        return Result.success(result);
+    }
 }

+ 7 - 1
src/main/java/com/zsElectric/boot/business/mapper/CouponMapper.java

@@ -4,8 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.zsElectric.boot.business.model.entity.Coupon;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.zsElectric.boot.business.model.query.CouponQuery;
+import com.zsElectric.boot.business.model.query.applet.AppCouponQuery;
 import com.zsElectric.boot.business.model.vo.CouponVO;
+import com.zsElectric.boot.business.model.vo.applet.AppCouponStatusNumVO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 优惠劵Mapper接口
@@ -23,6 +26,9 @@ public interface CouponMapper extends BaseMapper<Coupon> {
      * @param queryParams 查询参数
      * @return {@link Page<CouponVO>} 优惠劵分页列表
      */
-    Page<CouponVO> getCouponPage(Page<CouponVO> page, CouponQuery queryParams);
+    Page<CouponVO> getCouponPage(Page<CouponVO> page,@Param("queryParams") CouponQuery queryParams);
 
+    Page<CouponVO> getUserCouponPage(Page<Object> objectPage,@Param("queryParams") AppCouponQuery queryParams);
+
+    AppCouponStatusNumVO getCouponStatusNum(@Param("userId") Long userId);
 }

+ 2 - 1
src/main/java/com/zsElectric/boot/business/mapper/CouponTemplateMapper.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.zsElectric.boot.business.model.query.CouponTemplateQuery;
 import com.zsElectric.boot.business.model.vo.CouponTemplateVO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 优惠劵模板Mapper接口
@@ -23,6 +24,6 @@ public interface CouponTemplateMapper extends BaseMapper<CouponTemplate> {
      * @param queryParams 查询参数
      * @return {@link Page<CouponTemplateVO>} 优惠劵模板分页列表
      */
-    Page<CouponTemplateVO> getCouponTemplatePage(Page<CouponTemplateVO> page, CouponTemplateQuery queryParams);
+    Page<CouponTemplateVO> getCouponTemplatePage(Page<CouponTemplateVO> page,@Param("queryParams") CouponTemplateQuery queryParams);
 
 }

+ 4 - 0
src/main/java/com/zsElectric/boot/business/model/entity/BannerInfo.java

@@ -35,6 +35,10 @@ public class BannerInfo extends BaseEntity {
      * 跳转页面
      */
     private String jumpPage;
+    /**
+     * 位置 1-首页 2-个人中心
+     */
+    private String location;
     /**
      * 排序 越大越靠前
      */

+ 3 - 0
src/main/java/com/zsElectric/boot/business/model/form/BannerInfoForm.java

@@ -41,6 +41,9 @@ public class BannerInfoForm implements Serializable {
     @Size(max=255, message="跳转页面长度不能超过255个字符")
     private String jumpPage;
 
+    @Schema(description = "位置 1-首页 2-个人中心")
+    private Integer location;
+
     @Schema(description = "排序 越大越靠前")
     private Integer sort;
 

+ 0 - 1
src/main/java/com/zsElectric/boot/business/model/form/CouponTemplateForm.java

@@ -25,7 +25,6 @@ public class CouponTemplateForm implements Serializable {
     private static final long serialVersionUID = 1L;
 
     @Schema(description = "主键ID")
-    @NotNull(message = "主键ID不能为空")
     private Long id;
 
     @Schema(description = "优惠券码")

+ 14 - 0
src/main/java/com/zsElectric/boot/business/model/query/CouponTemplateQuery.java

@@ -19,4 +19,18 @@ import java.math.BigDecimal;
 @Setter
 public class CouponTemplateQuery extends BasePageQuery {
 
+    @Schema(description = "优惠劵名称")
+    private String name;
+
+    @Schema(description = "优惠劵状态:1-上线 2-下线")
+    private Integer status;
+
+    @Schema(description = "优惠劵类型:1-满减券 2-折扣券")
+    private Integer type;
+
+    @Schema(description = "开始时间")
+    private LocalDateTime startTime;
+
+    @Schema(description = "结束时间")
+    private LocalDateTime endTime;
 }

+ 25 - 0
src/main/java/com/zsElectric/boot/business/model/query/applet/AppCouponQuery.java

@@ -0,0 +1,25 @@
+package com.zsElectric.boot.business.model.query.applet;
+
+import com.zsElectric.boot.common.base.BasePageQuery;
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 优惠劵分页查询对象
+ *
+ * @author zsElectric
+ * @since 2025-12-19 09:58
+ */
+@Schema(description ="优惠劵查询对象")
+@Getter
+@Setter
+public class AppCouponQuery extends BasePageQuery {
+
+    @Schema(description = "用户ID", hidden = true)
+    private Long userId;
+
+    @Schema(description = "优惠券状态1-未使用 2-已使用 3-已过期")
+    private Integer status;
+}

+ 2 - 0
src/main/java/com/zsElectric/boot/business/model/vo/BannerInfoVO.java

@@ -34,6 +34,8 @@ public class BannerInfoVO implements Serializable {
     private String jumpAppid;
     @Schema(description = "跳转页面")
     private String jumpPage;
+    @Schema(description = "位置 1-首页 2-个人中心")
+    private String location;
     @Schema(description = "排序")
     private Integer sort;
     @Schema(description = "状态 0-禁用 1-启用")

+ 26 - 0
src/main/java/com/zsElectric/boot/business/model/vo/applet/AppCouponStatusNumVO.java

@@ -0,0 +1,26 @@
+package com.zsElectric.boot.business.model.vo.applet;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Getter
+@Setter
+@Schema(description = "小程序用户优惠券数量响应对象")
+public class AppCouponStatusNumVO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "未使用数量")
+    private Integer unusedNum;
+
+    @Schema(description = "已使用数量")
+    private Integer usedNum;
+
+    @Schema(description = "已过期数量")
+    private Integer expiredNum;
+}

+ 1 - 1
src/main/java/com/zsElectric/boot/business/service/AppletHomeService.java

@@ -30,7 +30,7 @@ public interface AppletHomeService {
      * 获取启用状态的Banner列表
      * @return Banner列表
      */
-    List<BannerInfoVO> getBannerList();
+    List<BannerInfoVO> getBannerList(Integer location);
 
     /**
      * 获取电站详情

+ 5 - 0
src/main/java/com/zsElectric/boot/business/service/CouponService.java

@@ -3,9 +3,11 @@ package com.zsElectric.boot.business.service;
 import com.zsElectric.boot.business.model.entity.Coupon;
 import com.zsElectric.boot.business.model.form.CouponForm;
 import com.zsElectric.boot.business.model.query.CouponQuery;
+import com.zsElectric.boot.business.model.query.applet.AppCouponQuery;
 import com.zsElectric.boot.business.model.vo.CouponVO;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.zsElectric.boot.business.model.vo.applet.AppCouponStatusNumVO;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
@@ -111,4 +113,7 @@ public interface CouponService extends IService<Coupon> {
      */
     java.util.List<Coupon> getCouponsByTemplateAndUser(Long templateId, Long userId);
 
+    IPage<CouponVO> getUserCouponPage(AppCouponQuery queryParams);
+
+    AppCouponStatusNumVO getCouponStatusNum(Long userId);
 }

+ 2 - 1
src/main/java/com/zsElectric/boot/business/service/impl/AppletHomeServiceImpl.java

@@ -115,11 +115,12 @@ public class AppletHomeServiceImpl implements AppletHomeService {
     }
 
     @Override
-    public List<BannerInfoVO> getBannerList() {
+    public List<BannerInfoVO> getBannerList(Integer location) {
         // 查询启用状态的Banner,按排序字段降序
         List<BannerInfo> bannerList = bannerInfoMapper.selectList(
                 new LambdaQueryWrapper<BannerInfo>()
                         .eq(BannerInfo::getStatus, 1)
+                        .eq(BannerInfo::getLocation, location)
                         .orderByDesc(BannerInfo::getSort)
         );
         return bannerInfoConverter.toVO(bannerList);

+ 18 - 0
src/main/java/com/zsElectric/boot/business/service/impl/CouponServiceImpl.java

@@ -1,9 +1,12 @@
 package com.zsElectric.boot.business.service.impl;
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.zsElectric.boot.business.model.query.applet.AppCouponQuery;
+import com.zsElectric.boot.business.model.vo.applet.AppCouponStatusNumVO;
 import com.zsElectric.boot.core.exception.CouponException;
 import com.zsElectric.boot.business.mapper.CouponTemplateMapper;
 import com.zsElectric.boot.business.model.entity.CouponTemplate;
+import com.zsElectric.boot.security.util.SecurityUtils;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -414,4 +417,19 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
                 .eq(Coupon::getUserId, userId));
     }
 
+    @Override
+    public IPage<CouponVO> getUserCouponPage(AppCouponQuery queryParams) {
+        queryParams.setUserId(SecurityUtils.getUserId());
+        Page<CouponVO> pageVO = this.baseMapper.getUserCouponPage(
+                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
+                queryParams
+        );
+        return pageVO;
+    }
+
+    @Override
+    public AppCouponStatusNumVO getCouponStatusNum(Long userId) {
+        return this.baseMapper.getCouponStatusNum(userId);
+    }
+
 }

+ 19 - 0
src/main/java/com/zsElectric/boot/business/service/impl/CouponTemplateServiceImpl.java

@@ -16,6 +16,7 @@ import com.zsElectric.boot.business.converter.CouponTemplateConverter;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Random;
 import java.util.stream.Collectors;
 
 import cn.hutool.core.lang.Assert;
@@ -68,9 +69,27 @@ public class CouponTemplateServiceImpl extends ServiceImpl<CouponTemplateMapper,
      */
     @Override
     public boolean saveCouponTemplate(CouponTemplateForm formData) {
+        formData.setCode(generateCouponCode());
         CouponTemplate entity = couponTemplateConverter.toEntity(formData);
         return this.save(entity);
     }
+
+    /**
+     * 基于时间戳生成优惠券号
+     */
+    public static String generateCouponCode() {
+        long timestamp = System.currentTimeMillis();
+        String timePart = String.valueOf(timestamp).substring(5); // 取部分时间戳
+
+        Random random = new Random();
+        String randomPart = String.format("%04d", random.nextInt(10000));
+
+        return "CPN" + timePart + randomPart;
+    }
+
+    public static void main(String[] args) {
+        System.out.println(generateCouponCode());
+    }
     
     /**
      * 更新优惠劵模板

+ 58 - 18
src/main/resources/mapper/business/CouponMapper.xml

@@ -5,27 +5,67 @@
     <!-- 获取优惠劵分页列表 -->
     <select id="getCouponPage" resultType="com.zsElectric.boot.business.model.vo.CouponVO">
         SELECT
-                id,
-                template_id,
-                name,
-                coupon_code,
-                status,
-                description,
-                user_id,
-                take_type,
-                take_time,
-                expire_time,
-                use_order_id,
-                use_time,
-                create_by,
-                create_time,
-                update_by,
-                update_time,
-                is_deleted
+        id,
+        template_id,
+        name,
+        coupon_code,
+        status,
+        description,
+        user_id,
+        take_type,
+        take_time,
+        expire_time,
+        use_order_id,
+        use_time,
+        create_by,
+        create_time,
+        update_by,
+        update_time,
+        is_deleted
         FROM
-            c_coupon
+        c_coupon
         <where>
         </where>
     </select>
+    <select id="getUserCouponPage" resultType="com.zsElectric.boot.business.model.vo.CouponVO">
+        SELECT
+        id,
+        template_id,
+        name,
+        coupon_code,
+        status,
+        description,
+        user_id,
+        take_type,
+        take_time,
+        expire_time,
+        use_order_id,
+        use_time,
+        create_by,
+        create_time,
+        update_by,
+        update_time,
+        is_deleted
+        FROM
+        c_coupon
+        <where>
+            is_deleted = 0
+            <if test="queryParams.userId != null">
+                and user_id = #{queryParams.userId}
+            </if>
+            <if test="queryParams.status != null">
+                and status = #{queryParams.status}
+            </if>
+        </where>
+    </select>
+    <select id="getCouponStatusNum" resultType="com.zsElectric.boot.business.model.vo.applet.AppCouponStatusNumVO">
+        SELECT
+            COUNT(CASE WHEN STATUS = 1 THEN 1 END) AS unusedNum,
+            COUNT(CASE WHEN STATUS = 2 THEN 1 END) AS usedNum,
+            COUNT(CASE WHEN STATUS = 3 THEN 1 END) AS expiredNum
+        FROM c_coupon
+        WHERE is_deleted = 0
+          AND user_id = #{userId}
+    </select>
 
 </mapper>

+ 3 - 0
src/main/resources/mapper/business/CouponTemplateMapper.xml

@@ -32,6 +32,9 @@
             <if test="queryParams.name != null and queryParams.name != ''">
                 AND name LIKE CONCAT('%', #{queryParams.name}, '%')
             </if>
+            <if test="queryParams.type != null">
+                AND type = #{queryParams.type}
+            </if>
             <if test="queryParams.status != null">
                 AND status = #{queryParams.status}
             </if>