Selaa lähdekoodia

我的动态粉丝不全显示

zhuli 1 kuukausi sitten
vanhempi
commit
6e08a00764
2 muutettua tiedostoa jossa 193 lisäystä ja 48 poistoa
  1. 3 0
      src/api/modules/newLoginApi.ts
  2. 190 48
      src/views/dynamicManagement/myDynamic.vue

+ 3 - 0
src/api/modules/newLoginApi.ts

@@ -122,6 +122,9 @@ export const getMyFollowed = (params: any) => {
 };
 
 //粉丝列表
+export const getMyStoreFans = (params: any) => {
+  return httpLogin.get(`/alienStore/stores/getMyStoreFans`, params);
+};
 export const getMyUserFans = (params: any) => {
   return httpLogin.get(`/alienStore/stores/getMyUserFans`, params);
 };

+ 190 - 48
src/views/dynamicManagement/myDynamic.vue

@@ -455,12 +455,12 @@
           </el-input>
         </div>
 
-        <!-- 用户列表 -->
-        <div class="relation-list">
+        <!-- 用户列表(一页5条,滚动到底自动加载) -->
+        <div ref="relationListScrollRef" class="relation-list" @scroll="onRelationListScroll">
           <div v-for="user in filteredRelationList" :key="user.id" class="relation-item">
             <div class="user-info-row">
               <div class="user-avatar-small">
-                <img v-if="user.image" :src="user.avatar" :alt="user.name" />
+                <img v-if="user.avatar" :src="user.avatar" :alt="user.name" />
                 <el-icon v-else :size="40">
                   <Avatar />
                 </el-icon>
@@ -470,7 +470,7 @@
                   {{ user.name }}
                 </div>
                 <div class="user-desc">
-                  {{ user.blurb }}
+                  {{ user.description }}
                 </div>
               </div>
             </div>
@@ -491,8 +491,18 @@
             </div>
           </div>
 
+          <!-- 触底加载哨兵(IntersectionObserver 检测可见时加载更多) -->
+          <div v-if="relationHasMore" ref="relationLoadMoreSentinelRef" class="relation-load-sentinel" />
+
+          <!-- 加载更多按钮(点击或滚到底都会触发) -->
+          <div v-if="relationHasMore" class="relation-load-more">
+            <el-button :loading="relationLoading" text type="primary" @click="loadMoreRelationList">
+              {{ relationLoading ? "加载中..." : "点击或滚动到底加载更多" }}
+            </el-button>
+          </div>
+
           <!-- 空状态 -->
-          <el-empty v-if="filteredRelationList.length === 0" description="暂无数据" />
+          <el-empty v-if="!relationLoading && filteredRelationList.length === 0" description="暂无数据" />
         </div>
       </div>
     </el-dialog>
@@ -699,7 +709,7 @@
 </template>
 
 <script setup lang="ts" name="myDynamic">
-import { ref, reactive, computed, onMounted } from "vue";
+import { ref, reactive, computed, onMounted, nextTick, watch } from "vue";
 import { useRouter } from "vue-router";
 import { ElMessage, ElMessageBox } from "element-plus";
 import {
@@ -732,6 +742,7 @@ import {
   getMyFollowed,
   addTransferCount,
   getMyUserFans,
+  getMyStoreFans,
   blockUser,
   likeDynamicNew,
   unlikeDynamicNew,
@@ -841,6 +852,52 @@ const relationDialogVisible = ref(false);
 const relationActiveTab = ref("friend");
 const relationSearch = ref("");
 const relationList = ref<RelationUser[]>([]);
+const relationPage = ref(1);
+const relationPageSize = 5;
+const relationTotal = ref(0);
+const relationLoading = ref(false);
+const relationHasMore = computed(() => relationList.value.length < relationTotal.value && !relationLoading.value);
+const relationListScrollRef = ref<HTMLElement | null>(null);
+const relationScrollTargets: HTMLElement[] = [];
+
+const onRelationListScroll = (e: Event) => {
+  const el = e.target as HTMLElement;
+  if (!el || !relationHasMore.value) return;
+  const { scrollTop, scrollHeight, clientHeight } = el;
+  const distanceToBottom = scrollHeight - scrollTop - clientHeight;
+  if (distanceToBottom < 80) {
+    loadMoreRelationList();
+  }
+};
+
+const bindRelationScroll = () => {
+  nextTick(() => {
+    setTimeout(() => {
+      const listEl = relationListScrollRef.value;
+      if (!listEl) return;
+      unbindRelationScroll();
+      listEl.addEventListener("scroll", onRelationListScroll, { passive: true });
+      relationScrollTargets.push(listEl);
+      const dialogBody = listEl.closest(".el-dialog")?.querySelector(".el-dialog__body") as HTMLElement | null;
+      if (dialogBody && dialogBody !== listEl) {
+        dialogBody.addEventListener("scroll", onRelationListScroll, { passive: true });
+        relationScrollTargets.push(dialogBody);
+      }
+    }, 100);
+  });
+};
+
+const unbindRelationScroll = () => {
+  relationScrollTargets.splice(0, relationScrollTargets.length).forEach(el => {
+    el.removeEventListener("scroll", onRelationListScroll);
+  });
+};
+
+watch(relationDialogVisible, visible => {
+  if (visible) bindRelationScroll();
+  else unbindRelationScroll();
+});
+
 //点击本地草稿
 const handleDraftClick = () => {
   router.push({
@@ -1721,59 +1778,128 @@ const handleRelationTabClick = (tab: any) => {
   }
 };
 //好友列表
-const handleFriendList = async () => {
+const mapRecordToRelationUser = (item: any, defaultStatus: "following" | "mutual" | "none" = "none"): RelationUser => ({
+  id: item.id || item.userId,
+  name: item.userName || item.nickname || item.name || "用户",
+  avatar: item.userImage || item.avatar || item.headImg || "",
+  description: item.description || item.bio || item.signature || "",
+  relationStatus: item.isFollowThis === 1 ? ("mutual" as const) : defaultStatus,
+  phoneId: item.phoneId || item.fansId || ""
+});
+
+const handleFriendList = async (append = false) => {
+  if (!append) {
+    relationPage.value = 1;
+    relationList.value = [];
+  }
   const phone = userStore.userInfo?.phone || "";
   const fansId = phone.startsWith("store_") ? phone : `store_${phone}`;
-  const res: any = await getMutualAttention({
-    page: 1,
-    size: 1000,
-    fansId: fansId,
-    name: relationSearch.value || ""
-  });
-  if (res.code == 200) {
-    const dataList = res.data?.records || [];
-    relationList.value = dataList;
+  relationLoading.value = true;
+  try {
+    const res: any = await getMutualAttention({
+      page: relationPage.value,
+      size: relationPageSize,
+      fansId,
+      name: relationSearch.value || ""
+    });
+    if (res.code == 200) {
+      const data = res.data;
+      const dataList = data?.records || data?.list || data || [];
+      const mapped = dataList.map((item: any) => mapRecordToRelationUser(item, "mutual"));
+      if (append) relationList.value.push(...mapped);
+      else relationList.value = mapped;
+      const currentLen = relationList.value.length;
+      if (dataList.length === 0) relationTotal.value = currentLen;
+      else if (typeof data?.total === "number" && currentLen >= data.total) relationTotal.value = data.total;
+      else relationTotal.value = currentLen + 1;
+    }
+  } finally {
+    relationLoading.value = false;
   }
 };
-//关注列表
-const handleFollowList = async () => {
+
+const handleFollowList = async (append = false) => {
+  if (!append) {
+    relationPage.value = 1;
+    relationList.value = [];
+  }
   const phone = userStore.userInfo?.phone || "";
   const fansId = phone.startsWith("store_") ? phone : `store_${phone}`;
-  const res: any = await getMyFollowed({
-    page: 1,
-    size: 1000,
-    fansId: fansId,
-    name: relationSearch.value || ""
-  });
-  if (res.code === 200) {
-    const dataList = res.data?.records || res.data?.list || res.data || [];
-    relationList.value = dataList;
+  relationLoading.value = true;
+  try {
+    const res: any = await getMyFollowed({
+      page: relationPage.value,
+      size: relationPageSize,
+      fansId,
+      name: relationSearch.value || ""
+    });
+    if (res.code === 200) {
+      const data = res.data;
+      const dataList = data?.records || data?.list || data || [];
+      const mapped = dataList.map((item: any) => mapRecordToRelationUser(item, "following"));
+      if (append) relationList.value.push(...mapped);
+      else relationList.value = mapped;
+      const currentLen = relationList.value.length;
+      if (dataList.length === 0) relationTotal.value = currentLen;
+      else if (typeof data?.total === "number" && currentLen >= data.total) relationTotal.value = data.total;
+      else relationTotal.value = currentLen + 1;
+    }
+  } finally {
+    relationLoading.value = false;
   }
 };
-//粉丝列表
-const handleFansList = async () => {
+
+const handleFansList = async (append = false) => {
+  if (!append) {
+    relationPage.value = 1;
+    relationList.value = [];
+  }
   const phone = userStore.userInfo?.phone || "";
   const fansId = phone.startsWith("store_") ? phone : `store_${phone}`;
-  const res: any = await getMyUserFans({
-    page: 1,
-    size: 1000,
-    fansId: fansId,
-    name: relationSearch.value || ""
-  });
-  if (res.code === 200) {
-    const dataList = res.data?.records || res.data?.list || res.data || [];
-    relationList.value = dataList.map((item: any) => ({
-      id: item.id || item.userId,
-      name: item.userName || item.nickname || item.name || "用户",
-      avatar: item.userImage || item.avatar || item.headImg || "",
-      description: item.description || item.bio || item.signature || "欢迎来这里",
-      // 粉丝列表需要判断是否互相关注
-      relationStatus: item.isFollowThis === 1 ? ("mutual" as const) : ("none" as const),
-      phoneId: item.phoneId || item.fansId || "" // 保存 phoneId 用于后续操作
-    }));
+  const name = relationSearch.value || "";
+  const listParams = { page: append ? relationPage.value : 1, size: append ? relationPageSize : 1000, fansId, name };
+  relationLoading.value = true;
+  try {
+    let dataList: any[] = [];
+    if (!append) {
+      const res1: any = await getMyStoreFans(listParams);
+      const res2: any = await getMyUserFans(listParams);
+      const records1 = res1?.code === 200 ? res1.data?.records || res1.data?.list || res1.data || [] : [];
+      const records2 = res2?.code === 200 ? res2.data?.records || res2.data?.list || res2.data || [] : [];
+      dataList = [...records1, ...records2];
+      const createdId = localGet("createdId") || userStore.userInfo?.storeId || "";
+      if (createdId) dataList = dataList.filter((item: any) => String(item.id) !== String(createdId));
+    } else {
+      const res: any = await getMyUserFans(listParams);
+      if (res.code === 200) {
+        const data = res.data;
+        dataList = data?.records || data?.list || data || [];
+        const createdId = localGet("createdId") || userStore.userInfo?.storeId || "";
+        if (createdId) dataList = dataList.filter((item: any) => String(item.id) !== String(createdId));
+      }
+    }
+    if (!append || dataList.length > 0) {
+      const mapped = dataList.map((item: any) => mapRecordToRelationUser(item, "none"));
+      if (append) relationList.value.push(...mapped);
+      else relationList.value = mapped;
+      const currentLen = relationList.value.length;
+      if (dataList.length === 0) relationTotal.value = currentLen;
+      else if (!append) relationTotal.value = currentLen;
+      else relationTotal.value = currentLen + 1;
+    }
+  } finally {
+    relationLoading.value = false;
   }
 };
 
+const loadMoreRelationList = () => {
+  if (!relationHasMore.value) return;
+  relationPage.value++;
+  if (relationActiveTab.value === "friend") handleFriendList(true);
+  else if (relationActiveTab.value === "follow") handleFollowList(true);
+  else handleFansList(true);
+};
+
 // 搜索关系列表
 const handleRelationSearch = () => {
   if (relationActiveTab.value === "friend") {
@@ -1831,6 +1957,9 @@ const handleUnfollow = async (user: RelationUser) => {
 const handleCloseRelationDialog = () => {
   relationSearch.value = "";
   relationList.value = [];
+  relationPage.value = 1;
+  relationTotal.value = 0;
+  unbindRelationScroll();
 };
 
 // 打开添加好友对话框
@@ -2760,18 +2889,27 @@ onMounted(() => {
   :deep(.el-dialog) {
     // 关系对话框
     .relation-dialog-content {
+      display: flex;
+      flex-direction: column;
+      max-height: 70vh;
+      overflow: hidden;
       .el-tabs {
+        flex-shrink: 0;
         margin-bottom: 16px;
         .el-tabs__header {
           margin-bottom: 16px;
         }
       }
       .search-box {
+        flex-shrink: 0;
         margin-bottom: 16px;
       }
       .relation-list {
-        max-height: 400px;
-        overflow-y: auto;
+        flex: 1;
+        min-height: 0;
+        max-height: 320px;
+        overflow: hidden auto;
+        -webkit-overflow-scrolling: touch;
         .relation-item {
           display: flex;
           align-items: center;
@@ -2827,6 +2965,10 @@ onMounted(() => {
             }
           }
         }
+        .relation-load-more {
+          padding: 12px 0;
+          text-align: center;
+        }
       }
     }