Просмотр исходного кода

开发我的券包 按店铺名称搜索优惠券列表功能 (漏功能)

lutong 1 день назад
Родитель
Сommit
aa244b4b2b

+ 14 - 5
alien-dining/src/main/java/shop/alien/dining/controller/DiningCouponController.java

@@ -41,7 +41,7 @@ public class DiningCouponController {
     /**
      * 获取该用户所有的优惠券列表
      */
-    @ApiOperation("获取该用户所有的优惠券列表。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券")
+    @ApiOperation("获取该用户所有的优惠券列表。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券;storeKeyword 非空时仅返回门店名称包含关键字的优惠券")
     @ApiOperationSupport(order = 9)
     @GetMapping("/getUserCouponList")
     @ApiImplicitParams({
@@ -50,7 +50,8 @@ public class DiningCouponController {
             @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "type", value = "券类型(不传或1:优惠券;代金券 type=4 已下线)", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false)
+            @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "storeKeyword", value = "店铺名称关键字,非空则只展示门店名称含关键字的优惠券(可选,最长100字符)", dataType = "String", paramType = "query", required = false)
     })
     public R<List<LifeDiscountCouponVo>> getUserCouponList(
             HttpServletRequest request,
@@ -59,10 +60,18 @@ public class DiningCouponController {
             @RequestParam("tabType") String tabType,
             @RequestParam(value = "type", required = false) Integer type,
             @RequestParam(value = "couponType", required = false) Integer couponType,
-            @RequestParam(value = "storeId", required = false) String storeId) {
-        log.info("DiningCouponController.getUserCouponList?page={}, size={}, tabType={}, type={}, couponType={}, storeId={}", page, size, tabType, type, couponType, storeId);
+            @RequestParam(value = "storeId", required = false) String storeId,
+            @RequestParam(value = "storeKeyword", required = false) String storeKeyword) {
+        String keywordParam = null;
+        if (storeKeyword != null) {
+            String t = storeKeyword.trim();
+            if (!t.isEmpty()) {
+                keywordParam = t.length() > 100 ? t.substring(0, 100) : t;
+            }
+        }
+        log.info("DiningCouponController.getUserCouponList?page={}, size={}, tabType={}, type={}, couponType={}, storeId={}, storeKeyword={}", page, size, tabType, type, couponType, storeId, keywordParam);
         String authorization = request.getHeader("Authorization");
-        return diningCouponService.getUserCouponList(authorization, page, size, tabType, type, couponType, storeId);
+        return diningCouponService.getUserCouponList(authorization, page, size, tabType, type, couponType, storeId, keywordParam);
     }
 
     /**

+ 3 - 1
alien-dining/src/main/java/shop/alien/dining/feign/AlienStoreFeign.java

@@ -55,6 +55,7 @@ public interface AlienStoreFeign {
      * @param type          券类型(不传:优惠券+代金券都返回,1:仅优惠券查 life_discount_coupon,4:仅代金券查 life_coupon)(可选)
      * @param couponType    优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选,仅当type不为4时有效)
      * @param storeId       商铺ID,可为空,传则仅返回该商铺的优惠券
+     * @param storeKeyword  店铺名称关键字,可为空,非空时仅返回门店名称包含关键字的优惠券
      * @return R.data 为 List&lt;LifeDiscountCouponVo&gt;
      */
     @GetMapping("life-discount-coupon/getUserCouponList")
@@ -65,7 +66,8 @@ public interface AlienStoreFeign {
             @RequestParam(value = "size", defaultValue = "10") int size,
             @RequestParam(value = "type", required = false) Integer type,
             @RequestParam(value = "couponType", required = false) Integer couponType,
-            @RequestParam(value = "storeId", required = false) String storeId);
+            @RequestParam(value = "storeId", required = false) String storeId,
+            @RequestParam(value = "storeKeyword", required = false) String storeKeyword);
 
     /**
      * 根据优惠券 ID 获取优惠券详情(含规则、门槛等)

+ 3 - 1
alien-dining/src/main/java/shop/alien/dining/service/DiningCouponService.java

@@ -26,9 +26,11 @@ public interface DiningCouponService {
      * @param tabType       0:全部(未使用),1:即将过期,2:已使用,3:已过期
      * @param type          券类型(不传:优惠券+代金券都返回,1:仅优惠券查 life_discount_coupon,4:仅代金券查 life_coupon)(可选)
      * @param couponType    优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选,仅当type不为4时有效)
+     * @param storeId       商铺ID(可选);传则 store 侧仅返回该商铺的优惠券
+     * @param storeKeyword   店铺名称关键字(可选);非空时仅门店名称包含关键字的券
      * @return R.data 为 List&lt;LifeDiscountCouponVo&gt;
      */
-    R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId);
+    R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeKeyword);
 
     /**
      * 根据优惠券 id 获取优惠券详情

+ 3 - 3
alien-dining/src/main/java/shop/alien/dining/service/impl/DiningCouponServiceImpl.java

@@ -40,8 +40,8 @@ public class DiningCouponServiceImpl implements DiningCouponService {
     private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
 
     @Override
-    public R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId) {
-        log.info("DiningCouponService.getUserCouponList page={}, size={}, tabType={}, type={}, couponType={}, storeId={}", page, size, tabType, type, couponType, storeId);
+    public R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeKeyword) {
+        log.info("DiningCouponService.getUserCouponList page={}, size={}, tabType={}, type={}, couponType={}, storeId={}, storeKeyword={}", page, size, tabType, type, couponType, storeId, storeKeyword);
         try {
             // 参数校验
             if (StringUtils.isEmpty(tabType)) {
@@ -55,7 +55,7 @@ public class DiningCouponServiceImpl implements DiningCouponService {
                 size = 10;
             }
             
-            R<List<LifeDiscountCouponVo>> result = alienStoreFeign.getUserCouponList(authorization, tabType, page, size, type, couponType, storeId);
+            R<List<LifeDiscountCouponVo>> result = alienStoreFeign.getUserCouponList(authorization, tabType, page, size, type, couponType, storeId, storeKeyword);
             if (result == null) {
                 log.error("Feign调用返回null");
                 return R.fail("获取优惠券列表失败:服务返回为空");

+ 15 - 0
alien-entity/src/main/java/shop/alien/mapper/LifeDiscountCouponUserMapper.java

@@ -9,6 +9,8 @@ import org.apache.ibatis.annotations.Select;
 import shop.alien.entity.store.LifeDiscountCouponUser;
 import shop.alien.entity.store.vo.LifeDiscountCouponUserWebVo;
 
+import java.time.LocalDate;
+
 /**
  * <p>
  * 优惠券用户表 Mapper 接口
@@ -29,4 +31,17 @@ public interface LifeDiscountCouponUserMapper extends BaseMapper<LifeDiscountCou
     @Select("select a.*, b.user_name, b.real_name, b.user_phone from life_discount_coupon_user a left join life_user b on a.user_id = b.id ${ew.customSqlSegment}")
     IPage<LifeDiscountCouponUserWebVo> selectPageList(IPage<LifeDiscountCouponUserWebVo> iPage, @Param(Constants.WRAPPER) QueryWrapper<LifeDiscountCouponUserWebVo> queryWrapper);
 
+    /**
+     * 用户券列表:先按模板(含逻辑删除模板)与用户 tab 筛选,再分页;与内存过滤后再分页语义一致。
+     */
+    IPage<LifeDiscountCouponUser> selectPageAfterTemplateFilter(IPage<LifeDiscountCouponUser> page,
+                                                                  @Param("userId") int userId,
+                                                                  @Param("tabType") String tabType,
+                                                                  @Param("today") LocalDate today,
+                                                                  @Param("sevenDaysLater") LocalDate sevenDaysLater,
+                                                                  @Param("sevenDaysAgo") LocalDate sevenDaysAgo,
+                                                                  @Param("couponType") Integer couponType,
+                                                                  @Param("filterStoreId") String filterStoreId,
+                                                                  @Param("storeKeyword") String storeKeyword);
+
 }

+ 39 - 0
alien-entity/src/main/resources/mapper/LifeDiscountCouponUserMapper.xml

@@ -19,4 +19,43 @@
         id, user_id, coupon_id, delete_flag, created_time, updated_time, created_user_id, updated_user_id
     </sql>
 
+    <select id="selectPageAfterTemplateFilter" resultType="shop.alien.entity.store.LifeDiscountCouponUser">
+        SELECT u.*
+        FROM life_discount_coupon_user u
+        INNER JOIN life_discount_coupon c ON u.coupon_id = c.id
+        LEFT JOIN store_info si ON si.id = c.store_id AND si.delete_flag = 0
+        WHERE u.delete_flag = 0
+          AND u.user_id = #{userId}
+          AND u.coupon_id IS NOT NULL
+        <choose>
+            <when test='tabType != null &amp;&amp; tabType.equals("0")'>
+                AND ((u.expiration_time &gt;= #{today}) OR u.expiration_time IS NULL)
+                AND u.status = 0
+            </when>
+            <when test='tabType != null &amp;&amp; tabType.equals("1")'>
+                AND u.expiration_time &gt;= #{today}
+                AND u.expiration_time &lt;= #{sevenDaysLater}
+                AND u.status = 0
+            </when>
+            <when test='tabType != null &amp;&amp; tabType.equals("2")'>
+                AND u.status = 1
+            </when>
+            <when test='tabType != null &amp;&amp; tabType.equals("3")'>
+                AND u.expiration_time &gt; #{sevenDaysAgo}
+                AND u.expiration_time &lt; #{today}
+                AND u.status = 0
+            </when>
+        </choose>
+        <if test="couponType != null">
+            AND c.coupon_type = #{couponType}
+        </if>
+        <if test="filterStoreId != null and filterStoreId != ''">
+            AND c.store_id = #{filterStoreId}
+        </if>
+        <if test="storeKeyword != null and storeKeyword != ''">
+            AND si.store_name LIKE CONCAT('%', #{storeKeyword}, '%')
+        </if>
+        ORDER BY u.created_time DESC
+    </select>
+
 </mapper>

+ 15 - 6
alien-store/src/main/java/shop/alien/store/controller/LifeDiscountCouponController.java

@@ -216,7 +216,7 @@ public class LifeDiscountCouponController {
     }
 
 
-    @ApiOperation("获取该用户所有的优惠券列表。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券")
+    @ApiOperation("获取该用户所有的优惠券列表。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券;storeKeyword 非空时仅返回门店名称包含关键字的优惠券")
     @ApiOperationSupport(order = 9)
     @GetMapping("/getUserCouponList")
     @ApiImplicitParams({@ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = false),
@@ -224,7 +224,8 @@ public class LifeDiscountCouponController {
             @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "type", value = "券类型(不传或传1:仅优惠券;代金券 type=4 已下线)", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false)
+            @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false),
+            @ApiImplicitParam(name = "storeKeyword", value = "店铺名称关键字,非空则只展示门店名称含关键字的优惠券(可选,最长100字符)", dataType = "String", paramType = "query", required = false)
     })
     public R<List<LifeDiscountCouponVo>> getUserCouponList(@ApiIgnore @TokenInfo UserLoginInfo userLoginInfo,
                                                            @RequestParam(value = "tabType") String tabType,
@@ -232,7 +233,8 @@ public class LifeDiscountCouponController {
                                                            @RequestParam(defaultValue = "10") int size,
                                                            @RequestParam(required = false) Integer type,
                                                            @RequestParam(value = "couponType", required = false) Integer couponType,
-                                                           @RequestParam(value = "storeId", required = false) String storeId) {
+                                                           @RequestParam(value = "storeId", required = false) String storeId,
+                                                           @RequestParam(value = "storeKeyword", required = false) String storeKeyword) {
         try {
             // 参数校验
             if (StringUtils.isEmpty(tabType)) {
@@ -250,12 +252,19 @@ public class LifeDiscountCouponController {
             if (couponType != null && couponType != 1 && couponType != 2) {
                 return R.fail("优惠券类型参数错误,必须为1(满减券)或2(折扣券)");
             }
+            String keywordParam = null;
+            if (storeKeyword != null) {
+                String t = storeKeyword.trim();
+                if (!t.isEmpty()) {
+                    keywordParam = t.length() > 100 ? t.substring(0, 100) : t;
+                }
+            }
             
-            log.info("LifeDiscountCouponController.getUserCouponList?userId={}, tabType={}, page={}, size={}, type={}, couponType={}, storeId={}", 
-                    userLoginInfo.getUserId(), tabType, page, size, type, couponType, storeId);
+            log.info("LifeDiscountCouponController.getUserCouponList?userId={}, tabType={}, page={}, size={}, type={}, couponType={}, storeId={}, storeKeyword={}",
+                    userLoginInfo.getUserId(), tabType, page, size, type, couponType, storeId, keywordParam);
             
             List<LifeDiscountCouponVo> storeCouponList = lifeDiscountCouponService.getUserCouponList(
-                    userLoginInfo, page, size, tabType, type, couponType, storeId);
+                    userLoginInfo, page, size, tabType, type, couponType, storeId, keywordParam);
             return R.data(storeCouponList);
         } catch (IllegalArgumentException e) {
             log.error("LifeDiscountCouponController.getUserCouponList 参数错误, userId={}, error={}", 

+ 2 - 1
alien-store/src/main/java/shop/alien/store/service/LifeDiscountCouponService.java

@@ -78,8 +78,9 @@ public interface LifeDiscountCouponService extends IService<LifeDiscountCoupon>
      * @param type 不传或1:仅用户优惠券(life_discount_coupon);4 已不再支持
      * @param couponType 优惠券类型:1=满减券,2=折扣券,null=全部
      * @param storeId 商铺ID,可为空,传则仅返回该商铺的优惠券
+     * @param storeKeyword 店铺名称关键字,非空时仅返回门店名称包含该关键字的券(与 storeId 可同时生效)
      */
-    List<LifeDiscountCouponVo> getUserCouponList(UserLoginInfo userLoginInfo, int page, int size, String tabType, Integer type, Integer couponType, String storeId);
+    List<LifeDiscountCouponVo> getUserCouponList(UserLoginInfo userLoginInfo, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeKeyword);
 
     /**
      * 获取所有优惠券列表(分页)

+ 30 - 47
alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponServiceImpl.java

@@ -796,23 +796,43 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
      * @param type 券类型:保留兼容,仅 null 或 1(仅用户优惠券);4 已废弃
      * @param couponType 优惠券类型:1-满减券,2-折扣券,null-全部
      * @param storeId 商铺ID,可为空,传则仅返回该商铺的优惠券
+     * @param storeKeyword 店铺名称关键字,非空时仅门店名称匹配的券参与分页(与筛选后再分页一致)
      * @return 优惠券列表
      */
     @Override
-    public List<LifeDiscountCouponVo> getUserCouponList(UserLoginInfo userLoginInfo, int page, int size, String tabType, Integer type, Integer couponType, String storeId) {
+    public List<LifeDiscountCouponVo> getUserCouponList(UserLoginInfo userLoginInfo, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeKeyword) {
         validateGetUserCouponListParams(userLoginInfo, tabType, type);
 
         ZoneId zone = ZoneId.systemDefault();
         LocalDate today = LocalDate.now(zone);
 
-        LambdaQueryWrapper<LifeDiscountCouponUser> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(LifeDiscountCouponUser::getUserId, userLoginInfo.getUserId());
-        applyUserCouponTabTypeFilter(queryWrapper, tabType, today, today.plusDays(7), today.minusDays(7));
-        // 仅 life_discount_coupon 用户券(有 coupon_id);模板可能已被商家逻辑删除,下层用 includeDeleted 再查属性
-        queryWrapper.isNotNull(LifeDiscountCouponUser::getCouponId);
-        queryWrapper.orderByDesc(LifeDiscountCouponUser::getCreatedTime);
+        String filterStoreId = null;
+        if (storeId != null) {
+            String trimmed = storeId.trim();
+            if (!trimmed.isEmpty()) {
+                filterStoreId = trimmed;
+            }
+        }
+        String keyword = null;
+        if (storeKeyword != null) {
+            String t = storeKeyword.trim();
+            if (!t.isEmpty()) {
+                keyword = t;
+            }
+        }
+
+        // 联表先按模板 + tab + couponType + storeId + 店铺名称关键字筛选再分页(含商家逻辑删除的模板)
+        IPage<LifeDiscountCouponUser> pageResult = lifeDiscountCouponUserMapper.selectPageAfterTemplateFilter(
+                new Page<>(page, size),
+                userLoginInfo.getUserId(),
+                tabType,
+                today,
+                today.plusDays(7),
+                today.minusDays(7),
+                couponType,
+                filterStoreId,
+                keyword);
 
-        IPage<LifeDiscountCouponUser> pageResult = lifeDiscountCouponUserMapper.selectPage(new Page<>(page, size), queryWrapper);
         List<LifeDiscountCouponUser> userRows = pageResult.getRecords();
         if (userRows.isEmpty()) {
             return new ArrayList<>();
@@ -825,11 +845,8 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
 
         List<LifeDiscountCouponVo> result = new ArrayList<>();
         for (LifeDiscountCouponUser row : userRows) {
-            if (row.getCouponId() == null) {
-                continue;
-            }
-            LifeDiscountCoupon template = templateById.get(row.getCouponId());
-            if (template == null || !matchesUserCouponListFilters(template, couponType, storeId)) {
+            LifeDiscountCoupon template = row.getCouponId() == null ? null : templateById.get(row.getCouponId());
+            if (template == null) {
                 continue;
             }
             result.add(buildCouponVo(template, row, zone, today, storeByIdStr));
@@ -855,33 +872,6 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         }
     }
 
-    /** tabType:与用户券分页 tab 对齐的 SQL 条件(expiration/status) */
-    private void applyUserCouponTabTypeFilter(LambdaQueryWrapper<LifeDiscountCouponUser> queryWrapper, String tabType,
-                                              LocalDate today, LocalDate sevenDaysLater, LocalDate sevenDaysAgo) {
-        if (DiscountCouponEnum.ALL.getValue().equals(tabType)) {
-            // 未使用:过期日 >= 今天 或过期时间为 null;含「今天过期」仍可展示
-            queryWrapper.and(w -> w.ge(LifeDiscountCouponUser::getExpirationTime, today)
-                            .or().isNull(LifeDiscountCouponUser::getExpirationTime))
-                    .eq(LifeDiscountCouponUser::getStatus, DiscountCouponEnum.WAITING_USED.getValue());
-            return;
-        }
-        if (DiscountCouponEnum.BE_ABOUT_TO_EXPORE.getValue().equals(tabType)) {
-            queryWrapper.ge(LifeDiscountCouponUser::getExpirationTime, today)
-                    .le(LifeDiscountCouponUser::getExpirationTime, sevenDaysLater)
-                    .eq(LifeDiscountCouponUser::getStatus, DiscountCouponEnum.WAITING_USED.getValue());
-            return;
-        }
-        if (DiscountCouponEnum.HAVE_ALREADY_APPLIED.getValue().equals(tabType)) {
-            queryWrapper.eq(LifeDiscountCouponUser::getStatus, DiscountCouponEnum.HAVE_BEEN_USED.getValue());
-            return;
-        }
-        if (DiscountCouponEnum.HAVE_EXPIRED.getValue().equals(tabType)) {
-            queryWrapper.gt(LifeDiscountCouponUser::getExpirationTime, sevenDaysAgo)
-                    .lt(LifeDiscountCouponUser::getExpirationTime, today)
-                    .eq(LifeDiscountCouponUser::getStatus, DiscountCouponEnum.WAITING_USED.getValue());
-        }
-    }
-
     private List<LifeDiscountCoupon> loadCouponTemplatesIncludeDeleted(List<LifeDiscountCouponUser> userRows) {
         List<Integer> couponIds = userRows.stream()
                 .map(LifeDiscountCouponUser::getCouponId)
@@ -907,13 +897,6 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         return infos.stream().collect(Collectors.toMap(s -> s.getId().toString(), s -> s, (a, b) -> a));
     }
 
-    private boolean matchesUserCouponListFilters(LifeDiscountCoupon template, Integer couponType, String filterStoreId) {
-        if (couponType != null && !couponType.equals(template.getCouponType())) {
-            return false;
-        }
-        return StringUtils.isEmpty(filterStoreId) || filterStoreId.equals(template.getStoreId());
-    }
-
     /**
      * 构建优惠券VO
      */