Browse Source

店铺详情 更多推荐修改 回显好友门店+同行业门店 最多回显30条

qinxuyang 3 tuần trước cách đây
mục cha
commit
790fbf0c30

+ 1 - 2
alien-entity/src/main/java/shop/alien/mapper/StoreInfoMapper.java

@@ -182,8 +182,7 @@ public interface StoreInfoMapper extends BaseMapper<StoreInfo> {
             "left join store_dictionary e on e.type_name = 'storeType' and e.dict_id = a.store_type and e.delete_flag = 0 " +
             "${ew.customSqlSegment} " +
             "and a.store_position is not null and a.store_position != '' " +
-            "and ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(', REPLACE(#{position}, ',', ' '), ')' )), ST_GeomFromText(CONCAT('POINT(', REPLACE(a.store_position, ',', ' '), ')' ))) / 1000, 2) <= 1 " +
-            "order by distance3 asc limit 20")
+            "order by distance3 asc")
     List<StoreInfoVo> getMoreRecommendedStores(@Param(Constants.WRAPPER) QueryWrapper<StoreInfoVo> queryWrapper, @Param("position") String position);
 
     /**

+ 118 - 35
alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java

@@ -47,6 +47,7 @@ import shop.alien.store.util.GroupConstant;
 import shop.alien.store.util.ai.AiAuthTokenUtil;
 import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.DistanceUtil;
+import shop.alien.util.common.JwtUtil;
 import shop.alien.util.common.constant.CouponStatusEnum;
 import shop.alien.util.common.constant.CouponTypeEnum;
 import shop.alien.util.common.constant.OcrTypeEnum;
@@ -5071,9 +5072,6 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
             return Collections.emptyList();
         }
 
-        QueryWrapper<StoreInfoVo> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("a.delete_flag", 0).eq("b.delete_flag", 0);
-        //如果查询未过期
         // 获取当前时刻
         Date currentDate = new Date();
         // 获取当前日期和时间
@@ -5085,49 +5083,134 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         calendar.set(Calendar.MILLISECOND, 0);
         // 加上 30 天
         calendar.add(Calendar.DAY_OF_MONTH, 30);
-        // 如果 expiration_time 为空则不做过期判断;如果不为空则要求大于当前时间
-        queryWrapper.and(w -> w.isNull("a.expiration_time")
-                .or()
-                .gt("a.expiration_time", currentDate));
-
-        // 如果 food_licence_expiration_time 为空则不做过期判断;如果不为空则要求大于当前时间
-        queryWrapper.and(w -> w.isNull("a.food_licence_expiration_time")
-                .or()
-                .gt("a.food_licence_expiration_time", currentDate));
+        // 构建position参数(格式:经度,纬度)
+        String position = lon + "," + lat;
 
-        // 构建一级分类
-        if (StringUtils.isNotEmpty(businessSection)) {
-            queryWrapper.eq("a.business_section", businessSection);
-            // 构建二级分类
-            if (StringUtils.isNotEmpty(businessTypes)) {
-                queryWrapper.eq("a.business_types", businessTypes);
-                // 构建三级分类
-                if (StringUtils.isNotEmpty(businessClassify)) {
-                    // 解析businessClassify参数(格式:1,2,3)
-                    String[] classifyArray = businessClassify.split(",");
-                    // 使用FIND_IN_SET函数检查数据库字段是否包含参数中的任何一个值
-                    queryWrapper.and(wrapper -> {
-                        for (int i = 0; i < classifyArray.length; i++) {
-                            String classify = classifyArray[i].trim();
-                            if (StringUtils.isNotEmpty(classify)) {
-                                if (i == 0) {
-                                    wrapper.apply("FIND_IN_SET({0}, a.business_classify) > 0", classify);
-                                } else {
-                                    wrapper.or().apply("FIND_IN_SET({0}, a.business_classify) > 0", classify);
+        // 先查询当前用户好友店铺ID(互相关注的商户)
+        Set<Integer> friendStoreIds = new HashSet<>();
+        try {
+            // 从上下文获取当前登录用户ID -> 查询手机号 -> 组装粉丝ID
+            JSONObject currentUserInfo = JwtUtil.getCurrentUserInfo();
+            if (currentUserInfo != null) {
+                Integer currentUserId = currentUserInfo.getInteger("userId");
+                if (currentUserId != null) {
+                    LifeUser currentUser = lifeUserMapper.selectById(currentUserId);
+                    if (currentUser != null && StringUtils.isNotEmpty(currentUser.getUserPhone())) {
+                        String myFansId = "user_" + currentUser.getUserPhone();
+
+                        // 我关注的店铺
+                        LambdaQueryWrapper<LifeFans> myFollowWrapper = new LambdaQueryWrapper<>();
+                        myFollowWrapper.eq(LifeFans::getFansId, myFansId)
+                                .likeRight(LifeFans::getFollowedId, "store_")
+                                .eq(LifeFans::getDeleteFlag, 0);
+                        List<LifeFans> myFollows = lifeFansMapper.selectList(myFollowWrapper);
+
+                        // 过滤出互相关注(店铺也关注我)的店铺phoneId:store_xxx
+                        Set<String> mutualStorePhones = new HashSet<>();
+                        if (!CollectionUtils.isEmpty(myFollows)) {
+                            List<String> followedStoreIds = myFollows.stream()
+                                    .map(LifeFans::getFollowedId)
+                                    .filter(Objects::nonNull)
+                                    .collect(Collectors.toList());
+
+                            if (!followedStoreIds.isEmpty()) {
+                                // 查询这些店铺是否关注我
+                                LambdaQueryWrapper<LifeFans> reciprocalWrapper = new LambdaQueryWrapper<>();
+                                reciprocalWrapper.in(LifeFans::getFansId, followedStoreIds)
+                                        .eq(LifeFans::getFollowedId, myFansId)
+                                        .eq(LifeFans::getDeleteFlag, 0);
+                                List<LifeFans> reciprocals = lifeFansMapper.selectList(reciprocalWrapper);
+                                Set<String> reciprocalFansIds = reciprocals.stream()
+                                        .map(LifeFans::getFansId)
+                                        .filter(Objects::nonNull)
+                                        .collect(Collectors.toSet());
+
+                                // 互相关注的店铺 phoneId(store_开头)
+                                for (String followedId : followedStoreIds) {
+                                    if (reciprocalFansIds.contains(followedId)) {
+                                        mutualStorePhones.add(followedId);
+                                    }
                                 }
                             }
                         }
-                    });
+
+                        if (!mutualStorePhones.isEmpty()) {
+                            // 提取店铺手机号
+                            Set<String> storePhones = mutualStorePhones.stream()
+                                    .map(pid -> {
+                                        int idx = pid.indexOf('_');
+                                        return idx != -1 ? pid.substring(idx + 1) : pid;
+                                    })
+                                    .collect(Collectors.toSet());
+
+                            // 根据店铺手机号查询 store_user,提取 store_id
+                            LambdaQueryWrapper<StoreUser> storeUserWrapper = new LambdaQueryWrapper<>();
+                            storeUserWrapper.in(StoreUser::getPhone, storePhones)
+                                    .eq(StoreUser::getDeleteFlag, 0);
+                            List<StoreUser> storeUsers = storeUserMapper.selectList(storeUserWrapper);
+                            friendStoreIds = storeUsers.stream()
+                                    .map(StoreUser::getStoreId)
+                                    .filter(Objects::nonNull)
+                                    .collect(Collectors.toSet());
+                        }
+                    }
                 }
             }
+        } catch (Exception e) {
+            // 好友优先不影响主流程
+            log.warn("更多推荐-好友店铺优先排序失败,忽略该步骤。error={}", e.getMessage());
         }
 
-        // 构建position参数(格式:经度,纬度)
-        String position = lon + "," + lat;
-        List<StoreInfoVo> storeInfoVoList = storeInfoMapper.getMoreRecommendedStores(queryWrapper, position);
+        // 查询好友店铺(不限制 business_section)
+        List<StoreInfoVo> friendStoreList = Collections.emptyList();
+        if (!friendStoreIds.isEmpty()) {
+            QueryWrapper<StoreInfoVo> friendQueryWrapper = new QueryWrapper<>();
+            friendQueryWrapper.eq("a.delete_flag", 0).eq("b.delete_flag", 0);
+            friendQueryWrapper.and(w -> w.isNull("a.expiration_time")
+                    .or()
+                    .gt("a.expiration_time", currentDate));
+            friendQueryWrapper.and(w -> w.isNull("a.food_licence_expiration_time")
+                    .or()
+                    .gt("a.food_licence_expiration_time", currentDate));
+            friendQueryWrapper.in("a.id", friendStoreIds);
+            friendStoreList = storeInfoMapper.getMoreRecommendedStores(friendQueryWrapper, position);
+        }
+
+        // 查询当前类型店铺(仅按 business_section)
+        QueryWrapper<StoreInfoVo> currentTypeQueryWrapper = new QueryWrapper<>();
+        currentTypeQueryWrapper.eq("a.delete_flag", 0).eq("b.delete_flag", 0);
+        currentTypeQueryWrapper.and(w -> w.isNull("a.expiration_time")
+                .or()
+                .gt("a.expiration_time", currentDate));
+        currentTypeQueryWrapper.and(w -> w.isNull("a.food_licence_expiration_time")
+                .or()
+                .gt("a.food_licence_expiration_time", currentDate));
+        if (StringUtils.isNotEmpty(businessSection)) {
+            currentTypeQueryWrapper.eq("a.business_section", businessSection);
+        }
+        List<StoreInfoVo> currentTypeStoreList = storeInfoMapper.getMoreRecommendedStores(currentTypeQueryWrapper, position);
+
+        // 合并:好友店铺在前,当前类型店铺在后;按店铺ID去重
+        Map<Integer, StoreInfoVo> mergedMap = new LinkedHashMap<>();
+        if (!CollectionUtils.isEmpty(friendStoreList)) {
+            for (StoreInfoVo vo : friendStoreList) {
+                mergedMap.put(vo.getId(), vo);
+            }
+        }
+        if (!CollectionUtils.isEmpty(currentTypeStoreList)) {
+            for (StoreInfoVo vo : currentTypeStoreList) {
+                mergedMap.putIfAbsent(vo.getId(), vo);
+            }
+        }
+        List<StoreInfoVo> storeInfoVoList = new ArrayList<>(mergedMap.values());
         if (CollectionUtils.isEmpty(storeInfoVoList)) {
             return Collections.emptyList();
         }
+
+        // 好友店铺 + 当前类型店铺,最多回显30个
+        if (storeInfoVoList.size() > 30) {
+            storeInfoVoList = new ArrayList<>(storeInfoVoList.subList(0, 30));
+        }
         // 提前查询所有需要的字典数据
         List<StoreInfoVo> collect = storeInfoVoList.stream().filter(record -> StringUtils.isNotEmpty(record.getStoreType())).collect(Collectors.toList());
         Set<String> allTypes = collect.stream().map(StoreInfoVo::getStoreType).flatMap(type -> Arrays.stream(type.split(","))).collect(Collectors.toSet());