Răsfoiți Sursa

提交 关注 取消关注 好友 粉丝 好友关系校验 判断 更改

lutong 10 ore în urmă
părinte
comite
ed25a51a50

+ 150 - 154
alien-entity/src/main/java/shop/alien/mapper/LifeFansMapper.java

@@ -18,42 +18,39 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
     @Select("<script>" +
             "select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, MAX(foll.blockedType) blockedType, MAX(foll.blockedId) blockedId, MAX(foll.username) username, MAX(foll.accountBlurb) accountBlurb, MAX(foll.isMerchant) isMerchant, MAX(foll.created_time) created_time, " +
             "  MAX(lb.id) blackListid, MAX(if(isnull(fans.id), 0, 1)) isFollowMe, MAX(if(isnull(fans_this.id), 0, 1)) isFollowThis, MAX(if(isnull(lb.id), '0', '1')) isBlocked,  " +
-            "  (select count(1) from life_fans where fans_id= foll.phoneId and delete_flag =0) followNum, " +
-            "  (select count(1) from life_fans where followed_id= foll.phoneId and delete_flag =0) fansNum from ( " +
+            "  (select count(1) from life_fans lf_cnt where lf_cnt.fans_user_type = foll.followedUserType and lf_cnt.fans_ref_id = foll.followedRefId and lf_cnt.delete_flag = 0) followNum, " +
+            "  (select count(1) from life_fans lf_cnt2 where lf_cnt2.followed_user_type = foll.followedUserType and lf_cnt2.followed_ref_id = foll.followedRefId and lf_cnt2.delete_flag = 0) fansNum from ( " +
             "    with follow as (   " +
-            "        select substring_index(followed_id, '_', 1) as flag, substring_index(followed_id, '_', -1) as phone, created_time   " +
+            "        select followed_user_type as followedUserType, followed_ref_id as followedRefId, created_time   " +
             "        from life_fans   " +
-            "        where delete_flag = 0 and (fans_id = #{fansId} " +
+            "        where delete_flag = 0 " +
             "<if test=\"identityUserType != null and identityRefId != null\">" +
-            "        or (fans_user_type = #{identityUserType} and fans_ref_id = #{identityRefId}) " +
+            "        and fans_user_type = #{identityUserType} and fans_ref_id = #{identityRefId} " +
             "</if>" +
-            ") " +
             "    )   " +
             "    select info.id, IF(info.store_application_status = 0, user.nick_name, info.store_name) AS NAME," +
-            "    user.head_img image, concat('store_', user.phone) phoneId, IF(info.store_application_status = 0, user.account_blurb, info.store_blurb) AS blurb, 1 blockedType,user.id blockedId ,IFNULL(user.nick_name, user.name) username, user.account_blurb accountBlurb, IF(info.store_application_status = 1, '1', '0') AS isMerchant, foll.created_time " +
+            "    user.head_img image, concat('store_', user.phone) phoneId, IF(info.store_application_status = 0, user.account_blurb, info.store_blurb) AS blurb, 1 blockedType,user.id blockedId ,IFNULL(user.nick_name, user.name) username, user.account_blurb accountBlurb, IF(info.store_application_status = 1, '1', '0') AS isMerchant, foll.created_time, 2 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join store_user user on foll.phone = user.phone " +
+            "    join store_user user on foll.followedUserType = 2 and user.id = foll.followedRefId " +
             "    join store_info info on info.id = user.store_id " +
             "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "    where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0 " +
+            "    where user.delete_flag = 0 and info.delete_flag = 0 " +
             "<if test=\"onlyStoreFollowed == false\">" +
             "    union " +
-            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId,'' username, '' accountBlurb, '0' AS isMerchant, foll.created_time " +
+            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId,'' username, '' accountBlurb, '0' AS isMerchant, foll.created_time, 1 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join life_user user on foll.phone = user.user_phone   " +
-            "    where foll.flag = 'user' and user.delete_flag = 0   " +
+            "    join life_user user on foll.followedUserType = 1 and user.id = foll.followedRefId   " +
+            "    where user.delete_flag = 0   " +
             "</if>" +
             ") foll   " +
-            "left join life_fans fans on fans.fans_id = foll.phoneId and fans.delete_flag = 0 and (fans.followed_id = #{relationFansId} " +
+            "left join life_fans fans on fans.fans_user_type = foll.followedUserType and fans.fans_ref_id = foll.followedRefId and fans.delete_flag = 0 " +
             "<if test=\"relationIdentityUserType != null and relationIdentityRefId != null\">" +
-            " or (fans.followed_user_type = #{relationIdentityUserType} and fans.followed_ref_id = #{relationIdentityRefId})" +
+            " and fans.followed_user_type = #{relationIdentityUserType} and fans.followed_ref_id = #{relationIdentityRefId} " +
             "</if>" +
-            ") " +
-            "left join life_fans fans_this on fans_this.followed_id = foll.phoneId and fans_this.delete_flag = 0 and (fans_this.fans_id = #{relationFansId} " +
+            "left join life_fans fans_this on fans_this.followed_user_type = foll.followedUserType and fans_this.followed_ref_id = foll.followedRefId and fans_this.delete_flag = 0 " +
             "<if test=\"relationIdentityUserType != null and relationIdentityRefId != null\">" +
-            " or (fans_this.fans_user_type = #{relationIdentityUserType} and fans_this.fans_ref_id = #{relationIdentityRefId})" +
+            " and fans_this.fans_user_type = #{relationIdentityUserType} and fans_this.fans_ref_id = #{relationIdentityRefId} " +
             "</if>" +
-            ") " +
             "left join life_blacklist lb on lb.blocked_type = foll.blockedType and lb.blocked_id = foll.blockedId and lb.blocker_type = #{blockerType} and lb.blocker_id = #{blockerId} and lb.delete_flag = 0 " +
             "${ew.customSqlSegment} " +
             "</script>")
@@ -63,106 +60,75 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
     @Select("<script>" +
             "select foll.*, if(isnull(fans.id), 0, 1) isFollowMe, 1 as isFollowThis from ( " +
             "    with follow as (   " +
-            "        select substring_index(followed_id, '_', 1) as flag, substring_index(followed_id, '_', -1) as phone   " +
+            "        select followed_user_type as followedUserType, followed_ref_id as followedRefId   " +
             "        from life_fans   " +
-            "        where delete_flag = 0 and (fans_id = #{fansId} " +
+            "        where delete_flag = 0 " +
             "<if test=\"identityUserType != null and identityRefId != null\">" +
-            "        or (fans_user_type = #{identityUserType} and fans_ref_id = #{identityRefId}) " +
+            "        and fans_user_type = #{identityUserType} and fans_ref_id = #{identityRefId} " +
             "</if>" +
-            ") " +
             "    )   " +
-            "    select info.id, info.store_name name, img.img_url image, concat('store_', user.phone) phoneId " +
+            "    select info.id, info.store_name name, img.img_url image, concat('store_', user.phone) phoneId, 2 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join store_user user on foll.phone = user.phone " +
+            "    join store_user user on foll.followedUserType = 2 and user.id = foll.followedRefId " +
             "    join store_info info on info.id = user.store_id " +
             "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "    where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0 " +
+            "    where user.delete_flag = 0 and info.delete_flag = 0 " +
             "    union " +
-            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId " +
+            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, 1 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join life_user user on foll.phone = user.user_phone   " +
-            "    where foll.flag = 'user' and user.delete_flag = 0   " +
+            "    join life_user user on foll.followedUserType = 1 and user.id = foll.followedRefId   " +
+            "    where user.delete_flag = 0   " +
             ") foll " +
-            "left join life_fans fans on fans.fans_id = foll.phoneId and fans.delete_flag = 0 and (fans.followed_id = #{fansId} " +
+            "left join life_fans fans on fans.fans_user_type = foll.followedUserType and fans.fans_ref_id = foll.followedRefId and fans.delete_flag = 0 " +
             "<if test=\"identityUserType != null and identityRefId != null\">" +
-            " or (fans.followed_user_type = #{identityUserType} and fans.followed_ref_id = #{identityRefId})" +
+            " and fans.followed_user_type = #{identityUserType} and fans.followed_ref_id = #{identityRefId}" +
             "</if>" +
-            ") " +
             "</script>")
     List<LifeFansVo> getMyFollowedAll(@Param("fansId") String fansId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId);
 
     @Select("<script>" +
             "select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, MAX(foll.blockedType) blockedType, MAX(foll.blockedId) blockedId, MAX(foll.isMerchant) isMerchant, MAX(foll.created_time) created_time, " +
             "  MAX(lb.id) blackListid, MAX(if(isnull(fans.id), 0, 1)) isFollowThis, MAX(if(isnull(fans_me.id), 0, 1)) isFollowMe, MAX(if(isnull(lb.id), '0', '1')) isBlocked, " +
-            "    (select count(1) from life_fans fans2 where fans2.followed_id = foll.phoneId and fans2.delete_flag = 0) fansNum, " +
-            "    (select count(1) from life_fans fans3 where fans3.fans_id = foll.phoneId and fans3.delete_flag = 0) followNum " +
+            "    (select count(1) from life_fans fans2 where fans2.followed_user_type = foll.fansUserType and fans2.followed_ref_id = foll.fansRefId and fans2.delete_flag = 0) fansNum, " +
+            "    (select count(1) from life_fans fans3 where fans3.fans_user_type = foll.fansUserType and fans3.fans_ref_id = foll.fansRefId and fans3.delete_flag = 0) followNum " +
             "from ( " +
             "    with follow as ( " +
-            "        select substring_index(fans_id, '_', 1) as flag, substring_index(fans_id, '_', -1) as phone, created_time " +
+            "        select fans_user_type as fansUserType, fans_ref_id as fansRefId, created_time " +
             "        from life_fans " +
-            "        where delete_flag = 0 and (followed_id = #{fansId} " +
+            "        where delete_flag = 0 " +
             "<if test=\"identityUserType != null and identityRefId != null\">" +
-            "        or (followed_user_type = #{identityUserType} and followed_ref_id = #{identityRefId}) " +
+            "        and followed_user_type = #{identityUserType} and followed_ref_id = #{identityRefId} " +
             "</if>" +
-            ") " +
             "    ) " +
-            "    select user.id, IF(info.store_application_status = 0, user.nick_name, info.store_name) AS name, user.head_img image, concat('store_', user.phone) phoneId, IF(info.store_application_status = 0, user.account_blurb, info.store_blurb) AS blurb, 1 blockedType,user.id blockedId, IF(info.store_application_status = 1, '1', '0') AS isMerchant, foll.created_time " +
+            "    select user.id, IF(info.store_application_status = 0, user.nick_name, info.store_name) AS name, user.head_img image, concat('store_', user.phone) phoneId, IF(info.store_application_status = 0, user.account_blurb, info.store_blurb) AS blurb, 1 blockedType,user.id blockedId, IF(info.store_application_status = 1, '1', '0') AS isMerchant, foll.created_time, 2 as fansUserType, user.id as fansRefId " +
             "    from follow foll " +
-            "    join store_user user on foll.phone = user.phone " +
+            "    join store_user user on foll.fansUserType = 2 and user.id = foll.fansRefId " +
             "    join store_info info on info.id = user.store_id " +
             "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "    where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0" +
+            "    where user.delete_flag = 0 and info.delete_flag = 0" +
             "<if test=\"onlyStoreFans == false\">" +
             "    union " +
-            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId, '0' AS isMerchant, foll.created_time " +
+            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId, '0' AS isMerchant, foll.created_time, 1 as fansUserType, user.id as fansRefId " +
             "    from follow foll " +
-            "    join life_user user on foll.phone = user.user_phone " +
-            "    where foll.flag = 'user' and user.delete_flag = 0 " +
+            "    join life_user user on foll.fansUserType = 1 and user.id = foll.fansRefId " +
+            "    where user.delete_flag = 0 " +
             "</if>" +
             ") foll " +
-            "left join life_fans fans on fans.followed_id = foll.phoneId and fans.delete_flag = 0 and (fans.fans_id = #{relationFansId} " +
+            "left join life_fans fans on fans.followed_user_type = foll.fansUserType and fans.followed_ref_id = foll.fansRefId and fans.delete_flag = 0 " +
             "<if test=\"relationIdentityUserType != null and relationIdentityRefId != null\">" +
-            " or (fans.fans_user_type = #{relationIdentityUserType} and fans.fans_ref_id = #{relationIdentityRefId})" +
+            " and fans.fans_user_type = #{relationIdentityUserType} and fans.fans_ref_id = #{relationIdentityRefId}" +
             "</if>" +
-            ") " +
-            "left join life_fans fans_me on fans_me.fans_id = foll.phoneId and fans_me.delete_flag = 0 and (fans_me.followed_id = #{relationFansId} " +
+            "left join life_fans fans_me on fans_me.fans_user_type = foll.fansUserType and fans_me.fans_ref_id = foll.fansRefId and fans_me.delete_flag = 0 " +
             "<if test=\"relationIdentityUserType != null and relationIdentityRefId != null\">" +
-            " or (fans_me.followed_user_type = #{relationIdentityUserType} and fans_me.followed_ref_id = #{relationIdentityRefId})" +
+            " and fans_me.followed_user_type = #{relationIdentityUserType} and fans_me.followed_ref_id = #{relationIdentityRefId}" +
             "</if>" +
-            ") " +
             "left join life_blacklist lb on lb.blocked_type = foll.blockedType and lb.blocked_id = foll.blockedId and lb.blocker_type = #{blockerType} and lb.blocker_id = #{blockerId} and lb.delete_flag = 0 " +
             "${ew.customSqlSegment} " +
             "</script>")
     IPage<LifeFansVo> getMyFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId, @Param("relationFansId") String relationFansId, @Param("relationIdentityUserType") Integer relationIdentityUserType, @Param("relationIdentityRefId") Integer relationIdentityRefId, @Param("blockerType") String blockerType, @Param("blockerId") String blockerId, @Param("onlyStoreFans") boolean onlyStoreFans, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
-//    @Select("select foll.*, if(isnull(fans.id), 0, 1) isFollowThis, 1 as isFollowMe, count(fans2.id) fansNum, count(fans3.id) followNum from ( " +
-//            "    with follow as ( " +
-//            "    select substring_index(fans_id, '_', 1) as flag, substring_index(fans_id, '_', -1) as phone " +
-//            "    from life_fans " +
-//            "    where delete_flag = 0 and followed_id = #{fansId} " +
-//            "    ) " +
-//            "    select info.id," +
-//            "    \"CASE \" +\n" +
-//            "        \"WHEN user.store_id IS NULL OR info.store_application_status = 0 THEN user.nick_name \" +\n" +
-//            "        \"ELSE info.store_name \" +\n" +
-//            "        \"END AS name, \" +\n" +
-//            "        \"CASE \" +\n" +
-//            "        \"WHEN user.store_id IS NULL OR info.store_application_status IN (0, 2) THEN user.account_blurb \" +\n" +
-//            "        \"ELSE info.store_blurb \" +\n" +
-//            "        \"END AS store_blurb, \" + " +
-//            "    user.head_img image, concat('store_', user.phone) phoneId" +
-//            "    from follow foll " +
-//            "    join store_user user on foll.phone = user.phone " +
-//            "    LEFT JOIN store_info info ON user.store_id IS NOT NULL AND info.id = user.store_id " +
-//            "    and info.delete_flag = 0" +
-//            "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-//            "    where foll.flag = 'store' and user.delete_flag = 0 " +
-//            ") foll " +
-//            "left join life_fans fans on fans.followed_id = foll.phoneId and fans.fans_id = #{fansId} and fans.delete_flag = 0 " +
-//            "left join life_fans fans2 on fans2.followed_id = foll.phoneId and fans2.delete_flag = 0 " +
-//            "left join life_fans fans3 on fans3.fans_id = foll.phoneId and fans3.delete_flag = 0 " +
-//            "${ew.customSqlSegment} ")
-    @Select("SELECT " +
+    @Select("<script>" +
+            "SELECT " +
             "MAX(foll.id) id, " +
             "MAX(foll.name) name, " +
             "MAX(foll.blurb) blurb, " +
@@ -176,14 +142,12 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
             "FROM " +
             "( " +
             "WITH follow AS ( " +
-            "SELECT " +
-            "substring_index(fans_id, '_', 1) AS flag, " +
-            "substring_index(fans_id, '_', -1) AS phone " +
-            "FROM " +
-            "life_fans " +
-            "WHERE " +
-            "delete_flag = 0 " +
-            "AND followed_id = #{fansId} " +
+            "SELECT fans_user_type AS fansUserType, fans_ref_id AS fansRefId " +
+            "FROM life_fans " +
+            "WHERE delete_flag = 0 AND fans_user_type = 2 " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "AND followed_user_type = #{identityUserType} AND followed_ref_id = #{identityRefId} " +
+            "</if>" +
             ") " +
             "SELECT " +
             "info.id, " +
@@ -200,119 +164,151 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
             "CASE " +
             "WHEN user.store_id IS NOT NULL AND info.store_application_status = 1 THEN '1' " +
             "ELSE '0' " +
-            "END AS isMerchant " +
-            "FROM " +
-            "follow foll " +
-            "JOIN store_user user ON foll.phone = user.phone " +
+            "END AS isMerchant, " +
+            "2 AS fansUserType, user.id AS fansRefId " +
+            "FROM follow foll " +
+            "JOIN store_user user ON foll.fansUserType = 2 AND user.id = foll.fansRefId " +
             "LEFT JOIN store_info info ON user.store_id IS NOT NULL " +
             "AND info.id = user.store_id " +
             "AND info.delete_flag = 0 " +
             "LEFT JOIN store_img img ON img.store_id = user.store_id " +
             "AND img.img_type = '10' " +
             "AND img.delete_flag = 0 " +
-            "WHERE " +
-            "foll.flag = 'store' " +
-            "AND user.delete_flag = 0 " +
+            "WHERE user.delete_flag = 0 " +
             ") foll " +
-            "LEFT JOIN life_fans fans ON fans.followed_id = foll.phoneId " +
-            "AND fans.fans_id = #{fansId} " +
+            "LEFT JOIN life_fans fans ON fans.followed_user_type = foll.fansUserType AND fans.followed_ref_id = foll.fansRefId " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "AND fans.fans_user_type = #{identityUserType} AND fans.fans_ref_id = #{identityRefId} " +
+            "</if>" +
             "AND fans.delete_flag = 0 " +
-            "LEFT JOIN life_fans fans2 ON fans2.followed_id = foll.phoneId " +
+            "LEFT JOIN life_fans fans2 ON fans2.followed_user_type = foll.fansUserType AND fans2.followed_ref_id = foll.fansRefId " +
             "AND fans2.delete_flag = 0 " +
-            "LEFT JOIN life_fans fans3 ON fans3.fans_id = foll.phoneId " +
+            "LEFT JOIN life_fans fans3 ON fans3.fans_user_type = foll.fansUserType AND fans3.fans_ref_id = foll.fansRefId " +
             "AND fans3.delete_flag = 0 " +
-            "${ew.customSqlSegment}")
-    IPage<LifeFansVo> getMyStoreFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
+            "${ew.customSqlSegment}" +
+            "</script>")
+    IPage<LifeFansVo> getMyStoreFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
-    @Select("select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, " +
+    @Select("<script>" +
+            "select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, " +
             "  MAX(if(isnull(fans.id), 0, 1)) isFollowThis, 1 as isFollowMe, " +
-            "       (select count(1) from life_fans fans2 where fans2.followed_id = foll.phoneId and fans2.delete_flag = 0) fansNum, " +
-            "       (select count(1) from life_fans fans3 where fans3.fans_id = foll.phoneId and fans3.delete_flag = 0) followNum " +
+            "       (select count(1) from life_fans fans2 where fans2.followed_user_type = foll.fansUserType and fans2.followed_ref_id = foll.fansRefId and fans2.delete_flag = 0) fansNum, " +
+            "       (select count(1) from life_fans fans3 where fans3.fans_user_type = foll.fansUserType and fans3.fans_ref_id = foll.fansRefId and fans3.delete_flag = 0) followNum " +
             " from ( " +
             "    with follow as ( " +
-            "    select substring_index(fans_id, '_', 1) as flag, substring_index(fans_id, '_', -1) as phone " +
+            "    select fans_user_type as fansUserType, fans_ref_id as fansRefId " +
             "    from life_fans " +
-            "    where delete_flag = 0 and followed_id = #{fansId} " +
+            "    where delete_flag = 0 and fans_user_type = 1 " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "    and followed_user_type = #{identityUserType} and followed_ref_id = #{identityRefId} " +
+            "</if>" +
             "    ) " +
-            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb " +
+            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 1 as fansUserType, user.id as fansRefId " +
             "    from follow foll " +
-            "    join life_user user on foll.phone = user.user_phone " +
-            "    where foll.flag = 'user' and user.delete_flag = 0 " +
+            "    join life_user user on foll.fansUserType = 1 and user.id = foll.fansRefId " +
+            "    where user.delete_flag = 0 " +
             ") foll " +
-            "left join life_fans fans on fans.followed_id = foll.phoneId and fans.fans_id = #{fansId} and fans.delete_flag = 0 " +
-            "${ew.customSqlSegment} ")
-    IPage<LifeFansVo> getMyUserFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
+            "left join life_fans fans on fans.followed_user_type = foll.fansUserType and fans.followed_ref_id = foll.fansRefId and fans.delete_flag = 0 " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            " and fans.fans_user_type = #{identityUserType} and fans.fans_ref_id = #{identityRefId}" +
+            "</if>" +
+            "${ew.customSqlSegment} " +
+            "</script>")
+    IPage<LifeFansVo> getMyUserFans(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
-    @Select("select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, MAX(foll.blockedType) blockedType, MAX(foll.blockedId) blockedId, MAX(foll.username) username, MAX(foll.accountBlurb) accountBlurb, MAX(foll.isMerchant) isMerchant, MAX(foll.created_time) created_time, " +
+    @Select("<script>" +
+            "select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, MAX(foll.blockedType) blockedType, MAX(foll.blockedId) blockedId, MAX(foll.username) username, MAX(foll.accountBlurb) accountBlurb, MAX(foll.isMerchant) isMerchant, MAX(foll.created_time) created_time, " +
             "  MAX(lb.id) blackListid, 1 as isFollowThis, 1 as isFollowMe, " +
-            "       (select count(1) from life_fans fans2 where fans2.followed_id = foll.phoneId and fans2.delete_flag = 0) fansNum, " +
-            "       (select count(1) from life_fans fans3 where fans3.fans_id = foll.phoneId and fans3.delete_flag = 0) followNum " +
+            "       (select count(1) from life_fans fans2 where fans2.followed_user_type = foll.followedUserType and fans2.followed_ref_id = foll.followedRefId and fans2.delete_flag = 0) fansNum, " +
+            "       (select count(1) from life_fans fans3 where fans3.fans_user_type = foll.followedUserType and fans3.fans_ref_id = foll.followedRefId and fans3.delete_flag = 0) followNum " +
             "from ( " +
             "    with follow as ( " +
-            "        select substring_index(fans1.followed_id, '_', 1) as flag, substring_index(fans1.followed_id, '_', -1) as phone, " +
+            "        select fans1.followed_user_type as followedUserType, fans1.followed_ref_id as followedRefId, " +
             "               GREATEST(fans1.created_time, fans2.created_time) as created_time " +
             "        from life_fans fans1 " +
-            "        join life_fans fans2 on fans1.followed_id = fans2.fans_id and fans1.fans_id = fans2.followed_id " +
-            "        where fans1.delete_flag = 0 and fans2.delete_flag = 0 and fans1.fans_id = #{fansId} " +
+            "        join life_fans fans2 on fans1.followed_user_type = fans2.fans_user_type and fans1.followed_ref_id = fans2.fans_ref_id " +
+            "            and fans1.fans_user_type = fans2.followed_user_type and fans1.fans_ref_id = fans2.followed_ref_id " +
+            "        where fans1.delete_flag = 0 and fans2.delete_flag = 0 " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "        and fans1.fans_user_type = #{identityUserType} and fans1.fans_ref_id = #{identityRefId} " +
+            "</if>" +
             "    ) " +
-            "    select info.id, IF(info.store_application_status = 0, user.nick_name, info.store_name) AS name, user.head_img image, concat('store_', user.phone) phoneId, IF(info.store_application_status = 0, user.account_blurb, info.store_blurb) AS blurb, 1 blockedType,user.id blockedId ,IFNULL(user.nick_name, user.name) username, user.account_blurb accountBlurb, IF(info.store_application_status = 1, '1', '0') AS isMerchant, foll.created_time " +
+            "    select info.id, IF(info.store_application_status = 0, user.nick_name, info.store_name) AS name, user.head_img image, concat('store_', user.phone) phoneId, IF(info.store_application_status = 0, user.account_blurb, info.store_blurb) AS blurb, 1 blockedType,user.id blockedId ,IFNULL(user.nick_name, user.name) username, user.account_blurb accountBlurb, IF(info.store_application_status = 1, '1', '0') AS isMerchant, foll.created_time, 2 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join store_user user on foll.phone = user.phone " +
+            "    join store_user user on foll.followedUserType = 2 and user.id = foll.followedRefId " +
             "    join store_info info on info.id = user.store_id " +
             "    left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "    where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0 " +
+            "    where user.delete_flag = 0 and info.delete_flag = 0 " +
             "    union " +
-            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId,'' username, '' accountBlurb, '0' AS isMerchant, foll.created_time " +
+            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 2 blockedType,user.id blockedId,'' username, '' accountBlurb, '0' AS isMerchant, foll.created_time, 1 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join life_user user on foll.phone = user.user_phone " +
-            "    where foll.flag = 'user' and user.delete_flag = 0 " +
+            "    join life_user user on foll.followedUserType = 1 and user.id = foll.followedRefId " +
+            "    where user.delete_flag = 0 " +
             ") foll " +
             "left join life_blacklist lb on lb.blocked_type = foll.blockedType and lb.blocked_id = foll.blockedId and lb.blocker_type = #{blockerType} and lb.blocker_id = #{blockerId} and lb.delete_flag = 0 " +
-            "${ew.customSqlSegment} ")
-    IPage<LifeFansVo> getMutualAttention(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("blockerType") String blockerType, @Param("blockerId") String blockerId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
+            "${ew.customSqlSegment} " +
+            "</script>")
+    IPage<LifeFansVo> getMutualAttention(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId, @Param("blockerType") String blockerType, @Param("blockerId") String blockerId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
-    @Select("select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, 1 as isFollowThis, 1 as isFollowMe, " +
-            "       (select count(1) from life_fans fans2 where fans2.followed_id = foll.phoneId and fans2.delete_flag = 0) fansNum, " +
-            "       (select count(1) from life_fans fans3 where fans3.fans_id = foll.phoneId and fans3.delete_flag = 0) followNum " +
+    @Select("<script>" +
+            "select MAX(foll.id) id, MAX(foll.name) name, MAX(foll.image) image, foll.phoneId, MAX(foll.blurb) blurb, 1 as isFollowThis, 1 as isFollowMe, " +
+            "       (select count(1) from life_fans fans2 where fans2.followed_user_type = foll.followedUserType and fans2.followed_ref_id = foll.followedRefId and fans2.delete_flag = 0) fansNum, " +
+            "       (select count(1) from life_fans fans3 where fans3.fans_user_type = foll.followedUserType and fans3.fans_ref_id = foll.followedRefId and fans3.delete_flag = 0) followNum " +
             "from ( " +
             "    with follow as ( " +
-            "        select substring_index(fans1.followed_id, '_', 1) as flag, substring_index(fans1.followed_id, '_', -1) as phone " +
+            "        select fans1.followed_user_type as followedUserType, fans1.followed_ref_id as followedRefId " +
             "        from life_fans fans1 " +
-            "        join life_fans fans2 on fans1.followed_id = fans2.fans_id and fans1.fans_id = fans2.followed_id " +
-            "        where fans1.delete_flag = 0 and fans2.delete_flag = 0 and fans1.fans_id = #{fansId} " +
+            "        join life_fans fans2 on fans1.followed_user_type = fans2.fans_user_type and fans1.followed_ref_id = fans2.fans_ref_id " +
+            "            and fans1.fans_user_type = fans2.followed_user_type and fans1.fans_ref_id = fans2.followed_ref_id " +
+            "        where fans1.delete_flag = 0 and fans2.delete_flag = 0 " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "        and fans1.fans_user_type = #{identityUserType} and fans1.fans_ref_id = #{identityRefId} " +
+            "</if>" +
             "    ) " +
-            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb " +
+            "    select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb, 1 as followedUserType, user.id as followedRefId " +
             "    from follow foll " +
-            "    join life_user user on foll.phone = user.user_phone " +
-            "    where foll.flag = 'user' and user.delete_flag = 0 " +
+            "    join life_user user on foll.followedUserType = 1 and user.id = foll.followedRefId " +
+            "    where user.delete_flag = 0 " +
             ") foll " +
-            "${ew.customSqlSegment} ")
-    IPage<LifeFansVo> getMutualAttentionUser(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
+            "${ew.customSqlSegment} " +
+            "</script>")
+    IPage<LifeFansVo> getMutualAttentionUser(IPage<LifeFansVo> iPage, @Param("fansId") String fansId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> wrapper);
 
-    @Select("select (select count(1) from life_fans where fans_id = #{phoneId} and delete_flag = 0 and followed_id not REGEXP '_$') followNum, " +
-            "(select count(1) from life_fans where followed_id= #{phoneId} and delete_flag = 0 and fans_id not REGEXP '_$') fansNum, " +
+    @Select("<script>" +
+            "select " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "(select count(1) from life_fans where delete_flag = 0 and fans_user_type = #{identityUserType} and fans_ref_id = #{identityRefId}) followNum, " +
+            "(select count(1) from life_fans where delete_flag = 0 and followed_user_type = #{identityUserType} and followed_ref_id = #{identityRefId}) fansNum, " +
+            "</if>" +
+            "<if test=\"identityUserType == null or identityRefId == null\">" +
+            "0 followNum, 0 fansNum, " +
+            "</if>" +
             "(select count(1) from ( " +
             "        select foll.*, 1 as isFollowThis, 1 as isFollowMe, " +
-            "               (select count(1) from life_fans fans2 where fans2.followed_id = foll.phoneId and fans2.delete_flag = 0) fansNum, " +
-            "               (select count(1) from life_fans fans3 where fans3.fans_id = foll.phoneId and fans3.delete_flag = 0) followNum " +
+            "               (select count(1) from life_fans fans2 where fans2.followed_user_type = foll.followedUserType and fans2.followed_ref_id = foll.followedRefId and fans2.delete_flag = 0) fansNum, " +
+            "               (select count(1) from life_fans fans3 where fans3.fans_user_type = foll.followedUserType and fans3.fans_ref_id = foll.followedRefId and fans3.delete_flag = 0) followNum " +
             "        from ( " +
             "            with follow as ( " +
-            "                select substring_index(fans1.followed_id, '_', 1) as flag, substring_index(fans1.followed_id, '_', -1) as phone " +
+            "                select fans1.followed_user_type as followedUserType, fans1.followed_ref_id as followedRefId " +
             "                from life_fans fans1 " +
-            "                join life_fans fans2 on fans1.followed_id = fans2.fans_id and fans1.fans_id = fans2.followed_id " +
-            "                where fans1.delete_flag = 0 and fans2.delete_flag = 0 and fans1.fans_id = #{phoneId} " +
+            "                join life_fans fans2 on fans1.followed_user_type = fans2.fans_user_type and fans1.followed_ref_id = fans2.fans_ref_id " +
+            "                    and fans1.fans_user_type = fans2.followed_user_type and fans1.fans_ref_id = fans2.followed_ref_id " +
+            "                where fans1.delete_flag = 0 and fans2.delete_flag = 0 " +
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "                and fans1.fans_user_type = #{identityUserType} and fans1.fans_ref_id = #{identityRefId} " +
+            "</if>" +
             "            ) " +
-            "            select info.id, info.store_name name, img.img_url image, concat('store_', user.phone) phoneId " +
+            "            select info.id, info.store_name name, img.img_url image, concat('store_', user.phone) phoneId, 2 as followedUserType, user.id as followedRefId " +
             "            from follow foll " +
-            "            join store_user user on foll.phone = user.phone " +
+            "            join store_user user on foll.followedUserType = 2 and user.id = foll.followedRefId " +
             "            join store_info info on info.id = user.store_id " +
             "            left join store_img img on img.store_id = user.store_id and img.img_type = '10' and img.delete_flag = 0 " +
-            "            where foll.flag = 'store' and user.delete_flag = 0 and info.delete_flag = 0 " +
+            "            where user.delete_flag = 0 and info.delete_flag = 0 " +
             "            union " +
-            "            select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId " +
+            "            select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, 1 as followedUserType, user.id as followedRefId " +
             "            from follow foll " +
-            "            join life_user user on foll.phone = user.user_phone " +
-            "            where foll.flag = 'user' and user.delete_flag = 0 " +
+            "            join life_user user on foll.followedUserType = 1 and user.id = foll.followedRefId " +
+            "            where user.delete_flag = 0 " +
             "        ) foll " +
             "    ) a " +
             ") friendNum, " +
@@ -320,10 +316,10 @@ public interface LifeFansMapper extends BaseMapper<LifeFans> {
             "    select count(id) " +
             "    from life_user_dynamics " +
             "    where delete_flag = 0 and draft = 0 and enable_status != 1 " +
-            "    and phone_user_type = (case when #{phoneId} like 'user\\_%' then 1 when #{phoneId} like 'store\\_%' then 2 when #{phoneId} like 'lawyer\\_%' then 3 else null end) " +
-            "    and phone_ref_id = (case when #{phoneId} like 'user\\_%' then (select id from life_user where concat('user_', user_phone) = #{phoneId} and delete_flag = 0 limit 1) " +
-            "      when #{phoneId} like 'store\\_%' then (select id from store_user where concat('store_', phone) = #{phoneId} and delete_flag = 0 limit 1) " +
-            "      when #{phoneId} like 'lawyer\\_%' then (select id from lawyer_user where concat('lawyer_', phone) = #{phoneId} and delete_flag = 0 limit 1) else null end) " +
-            ") dynamicsNum")
-    LifeFansVo getHomePageInfo(@Param("phoneId") String phoneId);
-}
+            "<if test=\"identityUserType != null and identityRefId != null\">" +
+            "    and phone_user_type = #{identityUserType} and phone_ref_id = #{identityRefId} " +
+            "</if>" +
+            ") dynamicsNum" +
+            "</script>")
+    LifeFansVo getHomePageInfo(@Param("phoneId") String phoneId, @Param("identityUserType") Integer identityUserType, @Param("identityRefId") Integer identityRefId);
+}

+ 7 - 3
alien-entity/src/main/java/shop/alien/mapper/LifeUserDynamicsMapper.java

@@ -101,10 +101,14 @@ public interface LifeUserDynamicsMapper extends BaseMapper<LifeUserDynamics> {
             "  CASE WHEN lf.id is not null THEN 1 ELSE 0 END AS isFollowThis,\n" +
             "  CASE WHEN lf1.id is not null THEN 1 ELSE 0 END AS isFollowMe\n" +
             "from middle_lud\n" +
-            "left join life_fans lf on lf.fans_id = #{phoneId} and lf.followed_id = middle_lud.phoneId and lf.delete_flag = '0'\n" +
-            "left join life_fans lf1 on lf1.fans_id = middle_lud.phoneId and lf1.followed_id = #{phoneId} and lf1.delete_flag = '0'\n" +
+            "left join life_fans lf on lf.fans_user_type = #{viewerUserType} and lf.fans_ref_id = #{viewerRefId} " +
+            "and lf.followed_user_type = middle_lud.phoneUserType and lf.followed_ref_id = middle_lud.phoneRefId and lf.delete_flag = 0\n" +
+            "left join life_fans lf1 on lf1.fans_user_type = middle_lud.phoneUserType and lf1.fans_ref_id = middle_lud.phoneRefId " +
+            "and lf1.followed_user_type = #{viewerUserType} and lf1.followed_ref_id = #{viewerRefId} and lf1.delete_flag = 0\n" +
             "order by middle_lud.like_created_time desc")
-    List<LifeUserDynamicsVo> selectDianZanList(String phoneId);
+    List<LifeUserDynamicsVo> selectDianZanList(@Param("phoneId") String phoneId,
+                                               @Param("viewerUserType") Integer viewerUserType,
+                                               @Param("viewerRefId") Integer viewerRefId);
 
     List<LifeUserDynamicsVo> getDynamicsList(@Param("nickName") String nickName, @Param("userType") String userType, @Param("dynamicsType") Integer dynamicsType, @Param("releaseStartTime") String releaseStartTime, @Param("releaseEndTime") String releaseEndTime, @Param("storeName") String storeName);
 

+ 147 - 0
alien-entity/src/main/java/shop/alien/util/type/LifeFansIdentityQuery.java

@@ -0,0 +1,147 @@
+package shop.alien.util.type;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.springframework.util.StringUtils;
+import shop.alien.entity.store.LifeFans;
+
+import java.util.Optional;
+
+/**
+ * life_fans 身份解析与查询:将 user_/store_/lawyer_ 前缀 phoneId 解析为 type + refId,
+ * 写入 fans_user_type / fans_ref_id / followed_user_type / followed_ref_id;
+ * 查询条件仅使用 type + refId(不依赖 fans_id / followed_id 字符串匹配)。
+ */
+public final class LifeFansIdentityQuery {
+
+    private LifeFansIdentityQuery() {
+    }
+
+    public static final class Scope {
+        private final String legacyPhoneId;
+        private final Integer userType;
+        private final Integer refId;
+
+        public Scope(String legacyPhoneId, Integer userType, Integer refId) {
+            this.legacyPhoneId = legacyPhoneId;
+            this.userType = userType;
+            this.refId = refId;
+        }
+
+        public String getLegacyPhoneId() {
+            return legacyPhoneId;
+        }
+
+        public Integer getUserType() {
+            return userType;
+        }
+
+        public Integer getRefId() {
+            return refId;
+        }
+
+        public boolean hasTypeRef() {
+            return userType != null && refId != null;
+        }
+    }
+
+    public static Scope resolve(String phoneId, TypeUtil typeUtil) {
+        if (!StringUtils.hasText(phoneId)) {
+            return new Scope(phoneId, null, null);
+        }
+        String key = phoneId.trim();
+        if (typeUtil != null && typeUtil.containsUnderscore(key)) {
+            PhoneTypeIdResult resolved = typeUtil.resolveTypeAndId(key);
+            if (resolved != null) {
+                return new Scope(key, resolved.getType(), resolved.getId());
+            }
+        }
+        return new Scope(key, null, null);
+    }
+
+    /**
+     * 写入关注记录时解析 fans_id / followed_id 并填充 type + ref 字段(不改变前端入参字符串)。
+     */
+    public static void fillIdentityOnFans(LifeFans lifeFans, TypeUtil typeUtil) {
+        if (lifeFans == null) {
+            return;
+        }
+        Scope fansScope = resolve(lifeFans.getFansId(), typeUtil);
+        if (fansScope.hasTypeRef()) {
+            lifeFans.setFansUserType(fansScope.getUserType());
+            lifeFans.setFansRefId(fansScope.getRefId());
+        }
+        Scope followedScope = resolve(lifeFans.getFollowedId(), typeUtil);
+        if (followedScope.hasTypeRef()) {
+            lifeFans.setFollowedUserType(followedScope.getUserType());
+            lifeFans.setFollowedRefId(followedScope.getRefId());
+        }
+    }
+
+    public static boolean hasCompletePairIdentity(LifeFans lifeFans) {
+        return lifeFans != null
+                && lifeFans.getFansUserType() != null
+                && lifeFans.getFansRefId() != null
+                && lifeFans.getFollowedUserType() != null
+                && lifeFans.getFollowedRefId() != null;
+    }
+
+    /**
+     * 回填后校验双方 type + ref 是否齐全;失败时返回错误文案。
+     */
+    public static Optional<String> validatePairIdentity(LifeFans lifeFans) {
+        if (lifeFans == null) {
+            return Optional.of("请求参数不能为空:请传入被关注方与粉丝标识");
+        }
+        if (lifeFans.getFansUserType() == null || lifeFans.getFansRefId() == null) {
+            return Optional.of("粉丝方标识(fansId)无法解析为有效用户,请检查格式或用户是否存在");
+        }
+        if (lifeFans.getFollowedUserType() == null || lifeFans.getFollowedRefId() == null) {
+            return Optional.of("被关注方标识(followedId)无法解析为有效用户,请检查格式或用户是否存在");
+        }
+        return Optional.empty();
+    }
+
+    public static void applyFansSide(LambdaQueryWrapper<LifeFans> wrapper, Scope scope) {
+        if (scope == null || !scope.hasTypeRef()) {
+            return;
+        }
+        wrapper.eq(LifeFans::getFansUserType, scope.getUserType())
+                .eq(LifeFans::getFansRefId, scope.getRefId());
+    }
+
+    public static void applyFollowedSide(LambdaQueryWrapper<LifeFans> wrapper, Scope scope) {
+        if (scope == null || !scope.hasTypeRef()) {
+            return;
+        }
+        wrapper.eq(LifeFans::getFollowedUserType, scope.getUserType())
+                .eq(LifeFans::getFollowedRefId, scope.getRefId());
+    }
+
+    public static void applyFansSide(LambdaUpdateWrapper<LifeFans> wrapper, Scope scope) {
+        if (scope == null || !scope.hasTypeRef()) {
+            return;
+        }
+        wrapper.eq(LifeFans::getFansUserType, scope.getUserType())
+                .eq(LifeFans::getFansRefId, scope.getRefId());
+    }
+
+    public static void applyFollowedSide(LambdaUpdateWrapper<LifeFans> wrapper, Scope scope) {
+        if (scope == null || !scope.hasTypeRef()) {
+            return;
+        }
+        wrapper.eq(LifeFans::getFollowedUserType, scope.getUserType())
+                .eq(LifeFans::getFollowedRefId, scope.getRefId());
+    }
+
+    /** 粉丝方 + 被关注方四维匹配(查重、互关等)。 */
+    public static void applyPair(LambdaQueryWrapper<LifeFans> wrapper, Scope fansScope, Scope followedScope) {
+        applyFansSide(wrapper, fansScope);
+        applyFollowedSide(wrapper, followedScope);
+    }
+
+    public static void applyPairWithDeleteFlag(LambdaQueryWrapper<LifeFans> wrapper, Scope fansScope, Scope followedScope) {
+        wrapper.eq(LifeFans::getDeleteFlag, 0);
+        applyPair(wrapper, fansScope, followedScope);
+    }
+}

+ 75 - 0
alien-entity/src/main/resources/db/migration/life_fans_type_ref_backfill.sql

@@ -0,0 +1,75 @@
+-- life_fans:历史数据 type + ref_id 回填(PR-1)
+-- 执行前请备份;建议在从库验证后再上生产。
+-- 前缀规则:user_ -> 1 + life_user.id;store_ -> 2 + store_user.id;lawyer_ -> 3 + lawyer_user.id
+
+-- ---------------------------------------------------------------------------
+-- 1. fans 侧 fans_id
+-- ---------------------------------------------------------------------------
+UPDATE life_fans lf
+    INNER JOIN life_user lu ON lf.fans_id LIKE 'user\_%'
+        AND lu.user_phone = SUBSTRING(lf.fans_id, 6) AND lu.delete_flag = 0
+SET lf.fans_user_type = 1, lf.fans_ref_id = lu.id
+WHERE lf.fans_user_type IS NULL AND lf.fans_id LIKE 'user\_%';
+
+UPDATE life_fans lf
+    INNER JOIN store_user su ON lf.fans_id LIKE 'store\_%'
+        AND su.phone = SUBSTRING(lf.fans_id, 7) AND su.delete_flag = 0
+SET lf.fans_user_type = 2, lf.fans_ref_id = su.id
+WHERE lf.fans_user_type IS NULL AND lf.fans_id LIKE 'store\_%';
+
+UPDATE life_fans lf
+    INNER JOIN lawyer_user lwu ON lf.fans_id LIKE 'lawyer\_%'
+        AND lwu.phone = SUBSTRING(lf.fans_id, 8) AND lwu.delete_flag = 0
+SET lf.fans_user_type = 3, lf.fans_ref_id = lwu.id
+WHERE lf.fans_user_type IS NULL AND lf.fans_id LIKE 'lawyer\_%';
+
+-- ---------------------------------------------------------------------------
+-- 2. 被关注方 followed_id
+-- ---------------------------------------------------------------------------
+UPDATE life_fans lf
+    INNER JOIN life_user lu ON lf.followed_id LIKE 'user\_%'
+        AND lu.user_phone = SUBSTRING(lf.followed_id, 6) AND lu.delete_flag = 0
+SET lf.followed_user_type = 1, lf.followed_ref_id = lu.id
+WHERE lf.followed_user_type IS NULL AND lf.followed_id LIKE 'user\_%';
+
+UPDATE life_fans lf
+    INNER JOIN store_user su ON lf.followed_id LIKE 'store\_%'
+        AND su.phone = SUBSTRING(lf.followed_id, 7) AND su.delete_flag = 0
+SET lf.followed_user_type = 2, lf.followed_ref_id = su.id
+WHERE lf.followed_user_type IS NULL AND lf.followed_id LIKE 'store\_%';
+
+UPDATE life_fans lf
+    INNER JOIN lawyer_user lwu ON lf.followed_id LIKE 'lawyer\_%'
+        AND lwu.phone = SUBSTRING(lf.followed_id, 8) AND lwu.delete_flag = 0
+SET lf.followed_user_type = 3, lf.followed_ref_id = lwu.id
+WHERE lf.followed_user_type IS NULL AND lf.followed_id LIKE 'lawyer\_%';
+
+-- ---------------------------------------------------------------------------
+-- 3. 校验:未回填的有效关注记录(delete_flag=0 且四方 type/ref 任一为 NULL)
+-- ---------------------------------------------------------------------------
+-- SELECT id, fans_id, followed_id, fans_user_type, fans_ref_id, followed_user_type, followed_ref_id
+-- FROM life_fans
+-- WHERE delete_flag = 0
+--   AND (fans_user_type IS NULL OR fans_ref_id IS NULL
+--     OR followed_user_type IS NULL OR followed_ref_id IS NULL);
+
+-- ---------------------------------------------------------------------------
+-- 4. 可选:type+ref 维度唯一约束(确认无重复后再执行)
+-- ---------------------------------------------------------------------------
+-- DELETE FROM life_fans
+-- WHERE id IN (
+--     SELECT id FROM (
+--         SELECT lf.id AS id,
+--                ROW_NUMBER() OVER (
+--                    PARTITION BY lf.followed_user_type, lf.followed_ref_id, lf.fans_user_type, lf.fans_ref_id
+--                    ORDER BY CASE WHEN lf.delete_flag = 0 THEN 0 ELSE 1 END, lf.id ASC
+--                ) AS rn
+--         FROM life_fans lf
+--         WHERE lf.followed_user_type IS NOT NULL AND lf.followed_ref_id IS NOT NULL
+--           AND lf.fans_user_type IS NOT NULL AND lf.fans_ref_id IS NOT NULL
+--     ) ranked
+--     WHERE ranked.rn > 1
+-- );
+--
+-- ALTER TABLE life_fans
+--     ADD UNIQUE KEY uk_life_fans_type_ref_pair (followed_user_type, followed_ref_id, fans_user_type, fans_ref_id);

+ 10 - 0
alien-entity/src/main/resources/db/migration/phone_identity_user_type_ref_id.sql

@@ -77,6 +77,11 @@ UPDATE life_fans lf
 SET lf.fans_user_type = 2, lf.fans_ref_id = su.id
 WHERE lf.fans_user_type IS NULL AND lf.fans_id LIKE 'store\_%';
 
+UPDATE life_fans lf
+    INNER JOIN lawyer_user lwu ON lf.fans_id LIKE 'lawyer\_%' AND lwu.phone = SUBSTRING(lf.fans_id, 8) AND lwu.delete_flag = 0
+SET lf.fans_user_type = 3, lf.fans_ref_id = lwu.id
+WHERE lf.fans_user_type IS NULL AND lf.fans_id LIKE 'lawyer\_%';
+
 -- life_fans.followed_id
 UPDATE life_fans lf
     INNER JOIN life_user lu ON lf.followed_id LIKE 'user\_%' AND lu.user_phone = SUBSTRING(lf.followed_id, 6) AND lu.delete_flag = 0
@@ -88,6 +93,11 @@ UPDATE life_fans lf
 SET lf.followed_user_type = 2, lf.followed_ref_id = su.id
 WHERE lf.followed_user_type IS NULL AND lf.followed_id LIKE 'store\_%';
 
+UPDATE life_fans lf
+    INNER JOIN lawyer_user lwu ON lf.followed_id LIKE 'lawyer\_%' AND lwu.phone = SUBSTRING(lf.followed_id, 8) AND lwu.delete_flag = 0
+SET lf.followed_user_type = 3, lf.followed_ref_id = lwu.id
+WHERE lf.followed_user_type IS NULL AND lf.followed_id LIKE 'lawyer\_%';
+
 -- life_user_dynamics.phone_id
 UPDATE life_user_dynamics lud
     INNER JOIN life_user lu ON lud.phone_id LIKE 'user\_%' AND lu.user_phone = SUBSTRING(lud.phone_id, 6) AND lu.delete_flag = 0

+ 9 - 3
alien-entity/src/main/resources/mapper/LifeUserDynamicsMapper.xml

@@ -9,6 +9,8 @@
         ANY_VALUE(dyna1.dynamicsType) AS dynamicsType,
         ANY_VALUE(dyna1.title) AS title,
         ANY_VALUE(dyna1.phoneId) AS phoneId,
+        ANY_VALUE(dyna1.phoneUserType) AS phoneUserType,
+        ANY_VALUE(dyna1.phoneRefId) AS phoneRefId,
         ANY_VALUE(dyna1.context) AS context,
         ANY_VALUE(dyna1.image_path) AS image_path,
         ANY_VALUE(dyna1.address) AS address,
@@ -44,6 +46,8 @@
         ANY_VALUE(dyna.dynamicsType) AS dynamicsType,
         ANY_VALUE(dyna.title) AS title,
         ANY_VALUE(dyna.phoneId) AS phoneId,
+        ANY_VALUE(dyna.phoneUserType) AS phoneUserType,
+        ANY_VALUE(dyna.phoneRefId) AS phoneRefId,
         ANY_VALUE(dyna.context) AS context,
         ANY_VALUE(dyna.image_path) AS image_path,
         ANY_VALUE(dyna.address) AS address,
@@ -122,7 +126,7 @@
         -- 4. GROUP BY 仅保留主键 id(因 dyna.id 是唯一主键,ANY_VALUE() 包裹的列在同一 id 下值唯一)
         GROUP BY dyna.id
         ) dyna1
-        LEFT JOIN life_fans lf1 ON lf1.followed_id = dyna1.phoneId AND lf1.delete_flag = 0
+        LEFT JOIN life_fans lf1 ON lf1.followed_user_type = dyna1.phoneUserType AND lf1.followed_ref_id = dyna1.phoneRefId AND lf1.delete_flag = 0
         WHERE 1=1
         <if test="nickName != null and nickName != ''">
             AND dyna1.userName LIKE CONCAT('%', #{nickName}, '%')
@@ -188,7 +192,7 @@
         left join store_comment sc on sc.business_id = dyna.id and sc.business_type = 2 and sc.delete_flag = 0
         left join life_message lm on lm.business_id = dyna.id
         GROUP BY dyna.id order by  dyna.created_time desc) dyna1
-        left join life_fans lf1 on lf1.followed_id = dyna1.phoneId and lf1.delete_flag = 0
+        left join life_fans lf1 on lf1.followed_user_type = dyna1.phoneUserType and lf1.followed_ref_id = dyna1.phoneRefId and lf1.delete_flag = 0
         GROUP by dyna1.id order by dyna1.top_status desc, dyna1.top_time desc
     </select>
 
@@ -232,6 +236,8 @@
         dyna.id,
         ANY_VALUE(dyna.title) AS title,
         ANY_VALUE(dyna.phoneId) AS phoneId,
+        ANY_VALUE(dyna.phoneUserType) AS phoneUserType,
+        ANY_VALUE(dyna.phoneRefId) AS phoneRefId,
         ANY_VALUE(dyna.context) AS context,
         ANY_VALUE(dyna.image_path) AS image_path,
         ANY_VALUE(dyna.address) AS address,
@@ -325,7 +331,7 @@
         order by
         dyna.created_time desc) dyna1
         left join life_fans lf1 on
-        lf1.followed_id = dyna1.phoneId and lf1.delete_flag = 0
+        lf1.followed_user_type = dyna1.phoneUserType and lf1.followed_ref_id = dyna1.phoneRefId and lf1.delete_flag = 0
         GROUP by
         dyna1.id
         order by

+ 18 - 7
alien-store/src/main/java/shop/alien/store/service/LifeStoreService.java

@@ -18,7 +18,7 @@ import shop.alien.entity.store.vo.LifeUserVo;
 import shop.alien.entity.store.vo.StoreInfoVo;
 import shop.alien.mapper.*;
 import shop.alien.store.config.BaseRedisService;
-import shop.alien.store.util.LifeFansIdentityQuery;
+import shop.alien.util.type.LifeFansIdentityQuery;
 import shop.alien.util.common.ListToPage;
 import shop.alien.util.type.LifeCollectIdentityQuery;
 import shop.alien.util.type.TypeUtil;
@@ -161,7 +161,9 @@ public class LifeStoreService {
         QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
         wrapper.like(StringUtils.isNotEmpty(name), "foll.name", name);
         wrapper.groupBy("foll.phoneId");
-        IPage<LifeFansVo> myStoreFans = lifeFansMapper.getMyStoreFans(new Page<>(page, size), fansId, wrapper);
+        LifeFansIdentityQuery.Scope scope = LifeFansIdentityQuery.resolve(fansId, typeUtil);
+        IPage<LifeFansVo> myStoreFans = lifeFansMapper.getMyStoreFans(new Page<>(page, size), fansId,
+                scope.getUserType(), scope.getRefId(), wrapper);
         filterBlocked(fansId, myStoreFans);
         List<LifeFansVo> collect = myStoreFans.getRecords().stream().filter(x -> x.getIsBlocked().equals("0")).collect(Collectors.toList());
         myStoreFans.setRecords(collect);
@@ -176,7 +178,9 @@ public class LifeStoreService {
         QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
         wrapper.like(StringUtils.isNotEmpty(name), "foll.name", name);
         wrapper.groupBy("foll.phoneId");
-        IPage<LifeFansVo> myUserFans = lifeFansMapper.getMyUserFans(new Page<>(page, size), fansId, wrapper);
+        LifeFansIdentityQuery.Scope scope = LifeFansIdentityQuery.resolve(fansId, typeUtil);
+        IPage<LifeFansVo> myUserFans = lifeFansMapper.getMyUserFans(new Page<>(page, size), fansId,
+                scope.getUserType(), scope.getRefId(), wrapper);
         filterBlocked(fansId, myUserFans);
         List<LifeFansVo> collect = myUserFans.getRecords().stream().filter(x -> x.getIsBlocked().equals("0")).collect(Collectors.toList());
         myUserFans.setRecords(collect);
@@ -205,7 +209,9 @@ public class LifeStoreService {
             StoreUser myStoreUser = storeUserService.getUserByPhone(myselfStorePhone);
             blockerId = String.valueOf(myStoreUser.getId());
         }
-        IPage<LifeFansVo> mutualAttention = lifeFansMapper.getMutualAttention(new Page<>(page, size), fansId, blockerType, blockerId, wrapper);
+        LifeFansIdentityQuery.Scope scope = LifeFansIdentityQuery.resolve(fansId, typeUtil);
+        IPage<LifeFansVo> mutualAttention = lifeFansMapper.getMutualAttention(new Page<>(page, size), fansId,
+                scope.getUserType(), scope.getRefId(), blockerType, blockerId, wrapper);
         List<LifeFansVo> collect = mutualAttention.getRecords().stream().filter(x -> null == x.getBlackListid()).collect(Collectors.toList());
         mutualAttention.setRecords(collect);
         mutualAttention.setTotal(collect.size());
@@ -219,7 +225,9 @@ public class LifeStoreService {
         QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
         wrapper.like(StringUtils.isNotEmpty(name), "foll.name", name);
         wrapper.groupBy("foll.phoneId");
-        IPage<LifeFansVo> mutualAttention = lifeFansMapper.getMutualAttentionUser(new Page<>(page, size), fansId, wrapper);
+        LifeFansIdentityQuery.Scope scope = LifeFansIdentityQuery.resolve(fansId, typeUtil);
+        IPage<LifeFansVo> mutualAttention = lifeFansMapper.getMutualAttentionUser(new Page<>(page, size), fansId,
+                scope.getUserType(), scope.getRefId(), wrapper);
         filterBlocked(fansId, mutualAttention);
         List<LifeFansVo> collect = mutualAttention.getRecords().stream().filter(x -> x.getIsBlocked().equals("0")).collect(Collectors.toList());
         mutualAttention.setRecords(collect);
@@ -290,12 +298,15 @@ public class LifeStoreService {
         int fansNum = countFilteredRecords(phoneId, blockerType, blockerId, wrapper, pageSize,
                 (page, w) -> queryMyFans(page, phoneId, phoneId, blockerType, blockerId, false, w));
 
+        LifeFansIdentityQuery.Scope phoneScope = LifeFansIdentityQuery.resolve(phoneId, typeUtil);
+
         // 统计好友数量(过滤被拉黑的)
         int friendNum = countFilteredRecords(phoneId, blockerType, blockerId, wrapper, pageSize,
-                (page, w) -> lifeFansMapper.getMutualAttention(page, phoneId, blockerType, blockerId, w));
+                (page, w) -> lifeFansMapper.getMutualAttention(page, phoneId,
+                        phoneScope.getUserType(), phoneScope.getRefId(), blockerType, blockerId, w));
 
         // 获取基础信息(包含dynamicsNum)
-        LifeFansVo lifeFansVo = lifeFansMapper.getHomePageInfo(phoneId);
+        LifeFansVo lifeFansVo = lifeFansMapper.getHomePageInfo(phoneId, phoneScope.getUserType(), phoneScope.getRefId());
         if (lifeFansVo == null) {
             lifeFansVo = new LifeFansVo();
         }

+ 42 - 29
alien-store/src/main/java/shop/alien/store/service/LifeUserDynamicsService.java

@@ -21,8 +21,8 @@ import shop.alien.mapper.*;
 import shop.alien.store.util.LifeDynamicsIdentityHelper;
 import shop.alien.store.util.LifeDynamicsIdentityHelper.PublisherScope;
 import shop.alien.store.util.StoreLikeRecordIdentityHelper;
-import shop.alien.store.util.StoreLikeRecordIdentityHelper.StoreLikerScope;
 import shop.alien.util.common.constant.CommentSourceTypeEnum;
+import shop.alien.util.type.LifeFansIdentityQuery;
 
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
@@ -73,6 +73,39 @@ public class LifeUserDynamicsService extends ServiceImpl<LifeUserDynamicsMapper,
 
     private final StoreLikeRecordIdentityHelper lifeLikeIdentityHelper;
 
+    private LifeFansIdentityQuery.Scope resolveFansScope(String phoneId) {
+        PublisherScope scope = dynamicsIdentityHelper.resolveFromPhoneId(phoneId);
+        return new LifeFansIdentityQuery.Scope(scope.getLegacyPhoneId(), scope.getPhoneUserType(), scope.getPhoneRefId());
+    }
+
+    private List<String> queryFollowedIds(String phoneId) {
+        LifeFansIdentityQuery.Scope scope = resolveFansScope(phoneId);
+        if (!scope.hasTypeRef()) {
+            return Collections.emptyList();
+        }
+        LambdaQueryWrapper<LifeFans> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LifeFans::getDeleteFlag, 0);
+        LifeFansIdentityQuery.applyFansSide(wrapper, scope);
+        return lifeFansMapper.selectList(wrapper).stream()
+                .map(LifeFans::getFollowedId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
+    private List<String> queryFansIds(String phoneId) {
+        LifeFansIdentityQuery.Scope scope = resolveFansScope(phoneId);
+        if (!scope.hasTypeRef()) {
+            return Collections.emptyList();
+        }
+        LambdaQueryWrapper<LifeFans> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(LifeFans::getDeleteFlag, 0);
+        LifeFansIdentityQuery.applyFollowedSide(wrapper, scope);
+        return lifeFansMapper.selectList(wrapper).stream()
+                .map(LifeFans::getFansId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
 
     public int addLiulanCount(String id) {
         LambdaUpdateWrapper<LifeUserDynamics> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
@@ -202,22 +235,14 @@ public class LifeUserDynamicsService extends ServiceImpl<LifeUserDynamicsMapper,
             if (StringUtils.isEmpty(phoneId)) {
                 return Collections.emptyList();
             }
-            LambdaQueryWrapper<LifeFans> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(LifeFans::getFansId, phoneId);
-            return lifeFansMapper.selectList(wrapper).stream()
-                    .map(LifeFans::getFollowedId)
-                    .collect(Collectors.toList());
+            return queryFollowedIds(phoneId);
         });
 
         CompletableFuture<List<String>> fansListFuture = CompletableFuture.supplyAsync(() -> {
             if (StringUtils.isEmpty(phoneId)) {
                 return Collections.emptyList();
             }
-            LambdaQueryWrapper<LifeFans> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(LifeFans::getFollowedId, phoneId);
-            return lifeFansMapper.selectList(wrapper).stream()
-                    .map(LifeFans::getFansId)
-                    .collect(Collectors.toList());
+            return queryFansIds(phoneId);
         });
 
         CompletableFuture<List<String>> likeListFuture = CompletableFuture.supplyAsync(() -> {
@@ -504,34 +529,20 @@ public class LifeUserDynamicsService extends ServiceImpl<LifeUserDynamicsMapper,
         resultMap.put("phoneId", phoneId);
 
         // 查询好友的关注
-        LambdaQueryWrapper<LifeFans> lifeFansWrapper = new LambdaQueryWrapper<>();
-        lifeFansWrapper.eq(LifeFans::getFansId, phoneId);
-        List<LifeFans> lifeFansList = lifeFansMapper.selectList(lifeFansWrapper);
-        List<String> followList = lifeFansList.stream().map(LifeFans::getFollowedId).collect(Collectors.toList());
+        List<String> followList = queryFollowedIds(phoneId);
 
         resultMap.put("followListSum", followList.size());
 
         // 查询好友的粉丝
-        lifeFansWrapper = new LambdaQueryWrapper<>();
-        lifeFansWrapper.eq(LifeFans::getFollowedId, phoneId);
-        lifeFansList = lifeFansMapper.selectList(lifeFansWrapper);
-        List<String> fansList = lifeFansList.stream().map(LifeFans::getFansId).collect(Collectors.toList());
+        List<String> fansList = queryFansIds(phoneId);
 
         // 查询我的粉丝
-        lifeFansWrapper = new LambdaQueryWrapper<>();
-        lifeFansWrapper.eq(LifeFans::getFollowedId, myselfPhoneId);
-        List<LifeFans> mylifeFansList = lifeFansMapper.selectList(lifeFansWrapper);
-        List<String> myFansList = mylifeFansList.stream().map(LifeFans::getFansId).collect(Collectors.toList());
+        List<String> myFansList = queryFansIds(myselfPhoneId);
 
         resultMap.put("fansListSum", fansList.size());
 
         //通过phoneId查询userId
         // 判断 targetPhone 是否在 fansList 中 1 已关注 0 未关注
-        // 处理 fansList
-        fansList = lifeFansList.stream().map(LifeFans::getFansId)
-//                .map(id -> id.split("_")[id.split("_").length - 1])
-                .collect(Collectors.toList());
-
         int isFollowed = fansList.contains(myselfPhoneId) ? 1 : 0;
         resultMap.put("isFollowed", isFollowed);
         resultMap.put("isFollowedMe", myFansList.contains(phoneId) ? 1 : 0);
@@ -735,7 +746,9 @@ public class LifeUserDynamicsService extends ServiceImpl<LifeUserDynamicsMapper,
     }
 
     public List<LifeUserDynamicsVo> getDianZanList(String phoneId) {
-        List<LifeUserDynamicsVo> lifeUserDynamicsVos = lifeUserDynamicsMapper.selectDianZanList(phoneId);
+        PublisherScope viewerScope = dynamicsIdentityHelper.resolveFromPhoneId(phoneId);
+        List<LifeUserDynamicsVo> lifeUserDynamicsVos = lifeUserDynamicsMapper.selectDianZanList(
+                phoneId, viewerScope.getPhoneUserType(), viewerScope.getPhoneRefId());
 
 
         // TODO  bugfix: 过滤掉我拉黑的和拉黑我的。

+ 23 - 25
alien-store/src/main/java/shop/alien/store/service/LifeUserService.java

@@ -39,10 +39,9 @@ import shop.alien.store.feign.SecondServiceFeign;
 import shop.alien.store.service.clockin.ClockInRecommendCacheService;
 import shop.alien.store.service.dynamics.DynamicsRecommendCacheService;
 import shop.alien.store.util.FunctionMagic;
-import shop.alien.store.util.LifeFansIdentityQuery;
+import shop.alien.util.type.LifeFansIdentityQuery;
 import shop.alien.store.util.LifeDynamicsIdentityHelper;
 import shop.alien.util.type.LifeNoticeUtil;
-import shop.alien.util.type.PhoneTypeIdResult;
 import shop.alien.util.type.TypeUtil;
 
 import java.text.SimpleDateFormat;
@@ -159,26 +158,16 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
 
         try {
             fans.setCreatedTime(new Date());
-
-            Integer followedType = null;
-            Integer followedId  = null;
-            Integer fansType  = null;
-            Integer fansId  = null;
-            if ( typeUtil.containsUnderscore(fans.getFollowedId()) ){
-                PhoneTypeIdResult phoneTypeIdResult = typeUtil.resolveTypeAndId(fans.getFollowedId());
-                followedType = phoneTypeIdResult.getType();
-                followedId = phoneTypeIdResult.getId();
+            LifeFansIdentityQuery.fillIdentityOnFans(fans, typeUtil);
+            Optional<String> identityError = LifeFansIdentityQuery.validatePairIdentity(fans);
+            if (identityError.isPresent()) {
+                return LifeFansFollowOutcome.failure(identityError.get());
             }
-            if ( typeUtil.containsUnderscore(fans.getFansId()) ){
-                PhoneTypeIdResult phoneTypeIdResult = typeUtil.resolveTypeAndId(fans.getFansId());
-                fansType = phoneTypeIdResult.getType();
-                fansId = phoneTypeIdResult.getId();
 
-            }
-            fans.setFollowedUserType(followedType);
-            fans.setFollowedRefId(followedId);
-            fans.setFansUserType(fansType);
-            fans.setFansRefId(fansId);
+            Integer followedType = fans.getFollowedUserType();
+            Integer followedId = fans.getFollowedRefId();
+            Integer fansType = fans.getFansUserType();
+            Integer fansId = fans.getFansRefId();
             LambdaQueryWrapper<LifeFans> activeQ = new LambdaQueryWrapper<>();
             activeQ.eq(LifeFans::getFollowedUserType, followedType)
                     .eq(LifeFans::getFollowedRefId, followedId)
@@ -225,7 +214,8 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
         String a = StringUtils.trimToEmpty(t != null ? t.getMessage() : "");
         String b = StringUtils.trimToEmpty(ex.getMessage());
         String m = (a + " | " + b).toLowerCase(Locale.ROOT);
-        return m.contains("duplicate") || m.contains("unique") || m.contains("uk_life_fans_follow_pair");
+        return m.contains("duplicate") || m.contains("unique") || m.contains("uk_life_fans_follow_pair")
+                || m.contains("uk_life_fans_type_ref_pair");
     }
 
     /**
@@ -438,9 +428,14 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
             return LifeFansFollowOutcome.failure(paramError.get());
         }
         try {
+            LifeFansIdentityQuery.fillIdentityOnFans(fans, typeUtil);
+            Optional<String> identityError = LifeFansIdentityQuery.validatePairIdentity(fans);
+            if (identityError.isPresent()) {
+                return LifeFansFollowOutcome.failure(identityError.get());
+            }
             LambdaUpdateWrapper<LifeFans> wrapper = new LambdaUpdateWrapper<>();
-            wrapper.eq(LifeFans::getFansId, fans.getFansId());
-            wrapper.eq(LifeFans::getFollowedId, fans.getFollowedId());
+            LifeFansIdentityQuery.applyFansSide(wrapper, LifeFansIdentityQuery.resolve(fans.getFansId(), typeUtil));
+            LifeFansIdentityQuery.applyFollowedSide(wrapper, LifeFansIdentityQuery.resolve(fans.getFollowedId(), typeUtil));
             int n = lifeFansMapper.delete(wrapper);
             if (n <= 0) {
                 return LifeFansFollowOutcome.success("当前未关注或已取消,无需重复操作");
@@ -487,13 +482,16 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
         LifeUser user = this.getOne(lambdaQueryWrapper);
         if (user != null) {
             String userId = "user_" + phoneNum;
+            LifeFansIdentityQuery.Scope userScope = new LifeFansIdentityQuery.Scope(userId, 1, user.getId());
             LambdaQueryWrapper<LifeFans> followWrapper = new LambdaQueryWrapper<>();
-            followWrapper.eq(LifeFans::getFansId, userId);
+            followWrapper.eq(LifeFans::getDeleteFlag, 0);
+            LifeFansIdentityQuery.applyFansSide(followWrapper, userScope);
             long followCount = lifeFansMapper.selectCount(followWrapper);
             user.setFollowCount((int) followCount);
 
             LambdaQueryWrapper<LifeFans> fansWrapper = new LambdaQueryWrapper<>();
-            fansWrapper.eq(LifeFans::getFollowedId, userId);
+            fansWrapper.eq(LifeFans::getDeleteFlag, 0);
+            LifeFansIdentityQuery.applyFollowedSide(fansWrapper, userScope);
             long fansCount = lifeFansMapper.selectCount(fansWrapper);
             user.setFansCount((int) fansCount);
 

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/impl/LifeFansServiceImpl.java

@@ -11,7 +11,7 @@ import shop.alien.mapper.LifeFansMapper;
 import shop.alien.mapper.LifeUserMapper;
 import shop.alien.mapper.StoreUserMapper;
 import shop.alien.store.service.LifeFansService;
-import shop.alien.store.util.LifeFansIdentityQuery;
+import shop.alien.util.type.LifeFansIdentityQuery;
 import shop.alien.util.type.TypeUtil;
 
 import java.util.*;

+ 11 - 4
alien-store/src/main/java/shop/alien/store/service/impl/LifeMessageServiceImpl.java

@@ -20,9 +20,11 @@ import shop.alien.store.service.LifeMessageService;
 import shop.alien.store.service.LifeUserService;
 import shop.alien.util.common.JwtUtil;
 import shop.alien.util.common.constant.LawyerStatusEnum;
+import shop.alien.util.type.LifeFansIdentityQuery;
 import shop.alien.util.type.LifeMessageUtil;
 import shop.alien.util.type.LifeNoticeUtil;
 import shop.alien.util.type.PhoneTypeIdResult;
+import shop.alien.util.type.TypeUtil;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -54,6 +56,8 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
 
     private final LifeNoticeUtil lifeNoticeUtil;
 
+    private final TypeUtil typeUtil;
+
     @Override
     public List<LifeMessageVo> getMessageList(String receiverId, int friendType, String search ,String userName) throws Exception {
         try {
@@ -108,16 +112,17 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 Map<String, String> chatEnabledCache = new HashMap<>();
 
                 // 当前用户的所有关注
+                LifeFansIdentityQuery.Scope receiverScope = LifeFansIdentityQuery.resolve(receiverId, typeUtil);
                 LambdaQueryWrapper<LifeFans> followWrapper = new LambdaQueryWrapper<>();
-                followWrapper.eq(LifeFans::getFansId, receiverId);
                 followWrapper.eq(LifeFans::getDeleteFlag, 0);
+                LifeFansIdentityQuery.applyFansSide(followWrapper, receiverScope);
                 List<LifeFans> followList = fansMapper.selectList(followWrapper);
                 List<String> followIds = followList.stream().map(LifeFans::getFollowedId).collect(Collectors.toList());
 
                 // 当前用户的所有粉丝
                 LambdaQueryWrapper<LifeFans> fansWrapper = new LambdaQueryWrapper<>();
-                fansWrapper.eq(LifeFans::getFollowedId, receiverId);
-                followWrapper.eq(LifeFans::getDeleteFlag, 0);
+                fansWrapper.eq(LifeFans::getDeleteFlag, 0);
+                LifeFansIdentityQuery.applyFollowedSide(fansWrapper, receiverScope);
                 List<LifeFans> fansList = fansMapper.selectList(fansWrapper);
                 List<String> fansIds = fansList.stream().map(LifeFans::getFansId).collect(Collectors.toList());
 
@@ -301,7 +306,9 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 blockerId = String.valueOf(myStoreUser.getId());
             }
 
-            List<LifeFansVo> lifeFansList = lifeFansMapper.getMutualAttention(new Page<>(1, Integer.MAX_VALUE), receiverId, blockerType, blockerId, wrapper).getRecords();
+            LifeFansIdentityQuery.Scope receiverScope = LifeFansIdentityQuery.resolve(receiverId, typeUtil);
+            List<LifeFansVo> lifeFansList = lifeFansMapper.getMutualAttention(new Page<>(1, Integer.MAX_VALUE), receiverId,
+                    receiverScope.getUserType(), receiverScope.getRefId(), blockerType, blockerId, wrapper).getRecords();
             List<String> friendsIds = lifeFansList.stream().map(LifeFansVo::getPhoneId).filter(item -> !item.equals(receiverId)).collect(Collectors.toList());
             String friendsIdsStr = "'" + String.join("','", friendsIds) + "'";
 

+ 0 - 85
alien-store/src/main/java/shop/alien/store/util/LifeFansIdentityQuery.java

@@ -1,85 +0,0 @@
-package shop.alien.store.util;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import shop.alien.entity.store.LifeFans;
-import shop.alien.util.type.PhoneTypeIdResult;
-import shop.alien.util.type.TypeUtil;
-
-/**
- * life_fans 查询条件:在原有 fans_id / followed_id 字符串匹配基础上,增加 type + refId 匹配。
- */
-public final class LifeFansIdentityQuery {
-
-    private LifeFansIdentityQuery() {
-    }
-
-    public static final class Scope {
-        private final String legacyPhoneId;
-        private final Integer userType;
-        private final Integer refId;
-
-        public Scope(String legacyPhoneId, Integer userType, Integer refId) {
-            this.legacyPhoneId = legacyPhoneId;
-            this.userType = userType;
-            this.refId = refId;
-        }
-
-        public String getLegacyPhoneId() {
-            return legacyPhoneId;
-        }
-
-        public Integer getUserType() {
-            return userType;
-        }
-
-        public Integer getRefId() {
-            return refId;
-        }
-
-        public boolean hasTypeRef() {
-            return userType != null && refId != null;
-        }
-    }
-
-    public static Scope resolve(String phoneId, TypeUtil typeUtil) {
-        if (phoneId == null) {
-            return new Scope(null, null, null);
-        }
-        Integer userType = null;
-        Integer refId = null;
-        if (typeUtil != null && typeUtil.containsUnderscore(phoneId)) {
-            PhoneTypeIdResult resolved = typeUtil.resolveTypeAndId(phoneId);
-            if (resolved != null) {
-                userType = resolved.getType();
-                refId = resolved.getId();
-            }
-        }
-        return new Scope(phoneId, userType, refId);
-    }
-
-    public static void applyFansSide(LambdaQueryWrapper<LifeFans> wrapper, Scope scope) {
-        if (scope == null || scope.getLegacyPhoneId() == null) {
-            return;
-        }
-        wrapper.and(q -> {
-            q.eq(LifeFans::getFansId, scope.getLegacyPhoneId());
-            if (scope.hasTypeRef()) {
-                q.or(sub -> sub.eq(LifeFans::getFansUserType, scope.getUserType())
-                        .eq(LifeFans::getFansRefId, scope.getRefId()));
-            }
-        });
-    }
-
-    public static void applyFollowedSide(LambdaQueryWrapper<LifeFans> wrapper, Scope scope) {
-        if (scope == null || scope.getLegacyPhoneId() == null) {
-            return;
-        }
-        wrapper.and(q -> {
-            q.eq(LifeFans::getFollowedId, scope.getLegacyPhoneId());
-            if (scope.hasTypeRef()) {
-                q.or(sub -> sub.eq(LifeFans::getFollowedUserType, scope.getUserType())
-                        .eq(LifeFans::getFollowedRefId, scope.getRefId()));
-            }
-        });
-    }
-}