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

feature: 我的动态添加好友功能,以及好友粉丝列表字段回显

sgc 2 месяцев назад
Родитель
Сommit
9e7a9605b1
2 измененных файлов с 360 добавлено и 22 удалено
  1. 11 0
      src/api/modules/newLoginApi.ts
  2. 349 22
      src/views/dynamicManagement/myDynamic.vue

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

@@ -364,3 +364,14 @@ export const cancelFollewed = (params: {
 }) => {
   return httpLogin.post(`/alienStore/user/cancelFollewed`, params);
 };
+
+// 搜索用户和店铺(根据手机号或昵称)
+export const getStoreAndUserByName = (params: {
+  page: number;
+  size: number;
+  phoneId: string; // store_手机号
+  userId: string | number;
+  searchName: string; // 搜索关键词(手机号或昵称)
+}) => {
+  return httpLogin.post(`/alienStore/user/getStoreAndUserByName`, params);
+};

+ 349 - 22
src/views/dynamicManagement/myDynamic.vue

@@ -22,6 +22,13 @@
               <span class="stat-item" @click="openRelationDialog('fans')">{{ userInfo.likeCount }} 粉丝</span>
             </div>
           </div>
+
+          <el-button type="primary" size="small" @click="addFriend" class="add-friend-btn">
+            <el-icon class="btn-icon">
+              <Plus />
+            </el-icon>
+            添加好友
+          </el-button>
         </div>
       </div>
 
@@ -453,7 +460,7 @@
           <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.avatar" :src="user.avatar" :alt="user.name" />
+                <img v-if="user.image" :src="user.avatar" :alt="user.name" />
                 <el-icon v-else :size="40">
                   <Avatar />
                 </el-icon>
@@ -463,7 +470,7 @@
                   {{ user.name }}
                 </div>
                 <div class="user-desc">
-                  {{ user.description }}
+                  {{ user.blurb }}
                 </div>
               </div>
             </div>
@@ -490,6 +497,78 @@
       </div>
     </el-dialog>
 
+    <!-- 添加好友对话框 -->
+    <el-dialog
+      v-model="addFriendDialogVisible"
+      title="添加好友"
+      width="500px"
+      destroy-on-close
+      @close="handleCloseAddFriendDialog"
+    >
+      <div class="add-friend-dialog-content">
+        <!-- 搜索框 -->
+        <div class="search-box">
+          <el-input
+            v-model="addFriendSearchKeyword"
+            placeholder="请输入手机号或昵称"
+            clearable
+            @keyup.enter="handleSearchFriend"
+            @input="handleSearchInput"
+            @clear="handleClearSearch"
+          >
+            <template #prefix>
+              <el-icon>
+                <Search />
+              </el-icon>
+            </template>
+          </el-input>
+        </div>
+
+        <!-- 搜索结果 -->
+        <div v-if="addFriendSearchKeyword" class="search-results">
+          <div v-if="addFriendSearching" class="search-loading">
+            <el-icon class="is-loading" :size="20">
+              <Loading />
+            </el-icon>
+            <span>搜索中...</span>
+          </div>
+          <div v-else-if="addFriendSearchResults.length > 0" class="search-results-list">
+            <div class="search-results-count">共{{ addFriendSearchResults.length }}个搜索结果</div>
+            <div v-for="user in addFriendSearchResults" :key="user.phoneId || user.id" class="search-result-item">
+              <div class="user-info-row">
+                <div class="user-avatar-small">
+                  <img v-if="user.imgUrl" :src="user.imgUrl || user.userAvatar" :alt="user.name || user.userName" />
+                  <el-icon v-else :size="40">
+                    <Avatar />
+                  </el-icon>
+                </div>
+                <div class="user-details">
+                  <div class="user-name-text">
+                    {{ user.storeUserName || "—" }}
+                  </div>
+                  <div class="user-desc">
+                    {{ user.blurb || "—" }}
+                  </div>
+                </div>
+              </div>
+              <div class="action-button">
+                <el-button v-if="user.isFollowThis == 1" type="primary" plain size="small" @click="handleUnfollowInSearch(user)">
+                  已关注
+                </el-button>
+                <el-button v-else type="primary" plain size="small" @click="handleFollowInSearch(user)"> 关注 </el-button>
+              </div>
+            </div>
+          </div>
+          <div v-else class="search-empty">
+            <el-empty description="暂无搜索结果" />
+          </div>
+        </div>
+        <div v-else class="search-placeholder">
+          <el-empty description="请输入手机号或昵称进行搜索" />
+        </div>
+      </div>
+    </el-dialog>
+
     <!-- 举报对话框 -->
     <el-dialog v-model="reportDialogVisible" title="举报理由" width="500px" destroy-on-close @close="handleCloseReportDialog">
       <div class="report-dialog-content">
@@ -638,7 +717,8 @@ import {
   Warning,
   Plus,
   CircleCheck,
-  CircleClose
+  CircleClose,
+  Loading
 } from "@element-plus/icons-vue";
 import {
   deleteDynamicsById,
@@ -654,7 +734,10 @@ import {
   getMyUserFans,
   blockUser,
   likeDynamicNew,
-  unlikeDynamicNew
+  unlikeDynamicNew,
+  getStoreAndUserByName,
+  toggleFollowUser,
+  cancelFollewed
 } from "@/api/modules/newLoginApi";
 import {} from "@/api/modules/dynamicManagement";
 import { useUserStore } from "@/stores/modules/user";
@@ -788,6 +871,12 @@ const shareSearch = ref("");
 const shareFriendList = ref<ShareFriend[]>([]);
 const selectedFriends = ref<number[]>([]);
 
+// 添加好友对话框相关
+const addFriendDialogVisible = ref(false);
+const addFriendSearchKeyword = ref("");
+const addFriendSearchResults = ref<any[]>([]);
+const addFriendSearching = ref(false);
+
 // 过滤后的好友列表
 const filteredShareFriendList = computed(() => {
   if (!shareSearch.value) {
@@ -1638,16 +1727,9 @@ const handleFriendList = async () => {
     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: "mutual" as const, // 好友列表都是互相关注
-      phoneId: item.phoneId || item.fansId || "" // 保存 phoneId 用于后续操作
-    }));
+  if (res.code == 200) {
+    const dataList = res.data?.records || [];
+    relationList.value = dataList;
   }
 };
 //关注列表
@@ -1662,14 +1744,7 @@ const handleFollowList = async () => {
   });
   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: "following" as const, // 关注列表都是已关注状态
-      phoneId: item.phoneId || item.followedId || "" // 保存 phoneId 用于后续操作
-    }));
+    relationList.value = dataList;
   }
 };
 //粉丝列表
@@ -1755,6 +1830,156 @@ const handleCloseRelationDialog = () => {
   relationList.value = [];
 };
 
+// 打开添加好友对话框
+const addFriend = () => {
+  addFriendDialogVisible.value = true;
+};
+
+// 关闭添加好友对话框
+const handleCloseAddFriendDialog = () => {
+  // 清空防抖定时器
+  if (searchDebounceTimer) {
+    clearTimeout(searchDebounceTimer);
+    searchDebounceTimer = null;
+  }
+  addFriendSearchKeyword.value = "";
+  addFriendSearchResults.value = [];
+  addFriendSearching.value = false;
+};
+
+// 搜索输入防抖定时器
+let searchDebounceTimer: NodeJS.Timeout | null = null;
+
+// 搜索输入处理(带防抖)
+const handleSearchInput = () => {
+  // 清空之前的定时器
+  if (searchDebounceTimer) {
+    clearTimeout(searchDebounceTimer);
+  }
+
+  // 如果输入框为空,清空搜索结果
+  if (!addFriendSearchKeyword.value.trim()) {
+    addFriendSearchResults.value = [];
+    return;
+  }
+
+  // 设置防抖,500ms后执行搜索
+  searchDebounceTimer = setTimeout(() => {
+    handleSearchFriend();
+  }, 200);
+};
+
+// 搜索好友
+const handleSearchFriend = async () => {
+  if (!addFriendSearchKeyword.value.trim()) {
+    addFriendSearchResults.value = [];
+    return;
+  }
+
+  addFriendSearching.value = true;
+  addFriendSearchResults.value = [];
+
+  try {
+    const phone = userStore.userInfo?.phone || "";
+    const currentUserPhoneId = phone.startsWith("store_") ? phone : `store_${phone}`;
+    const userId = userStore.userInfo?.id || userStore.userInfo?.userId || "";
+
+    const res: any = await getStoreAndUserByName({
+      page: 1,
+      size: 100,
+      phoneId: currentUserPhoneId,
+      userId: userId,
+      searchName: addFriendSearchKeyword.value.trim()
+    });
+
+    if (res && res.code === 200) {
+      // 处理搜索结果数据
+      const dataList = res.data?.records || [];
+      addFriendSearchResults.value = dataList;
+    } else {
+      ElMessage.error(res?.msg || res?.message || "搜索失败");
+    }
+  } catch (error: any) {
+    console.error("搜索好友失败:", error);
+    ElMessage.error(error?.message || "搜索失败,请重试");
+  } finally {
+    addFriendSearching.value = false;
+  }
+};
+
+// 清空搜索
+const handleClearSearch = () => {
+  // 清空防抖定时器
+  if (searchDebounceTimer) {
+    clearTimeout(searchDebounceTimer);
+    searchDebounceTimer = null;
+  }
+  addFriendSearchResults.value = [];
+};
+
+// 在搜索结果中关注用户
+const handleFollowInSearch = async (user: any) => {
+  try {
+    const phone = userStore.userInfo?.phone || "";
+    const currentUserPhoneId = phone.startsWith("store_") ? phone : `store_${phone}`;
+
+    if (!user.phoneId) {
+      ElMessage.error("用户信息不完整");
+      return;
+    }
+
+    await toggleFollowUser({
+      followedId: user.phoneId,
+      fansId: currentUserPhoneId,
+      fansType: 2
+    });
+
+    // 更新关注状态
+    user.isFollowed = 1;
+    user.isFollowThis = 1;
+
+    ElMessage.success("关注成功");
+  } catch (error: any) {
+    console.error("关注失败:", error);
+    ElMessage.error(error?.message || "关注失败,请重试");
+  }
+};
+
+// 在搜索结果中取消关注用户
+const handleUnfollowInSearch = async (user: any) => {
+  try {
+    await ElMessageBox.confirm("确定要取消关注吗?", "提示", {
+      confirmButtonText: "确定",
+      cancelButtonText: "取消",
+      type: "warning"
+    });
+
+    const phone = userStore.userInfo?.phone || "";
+    const currentUserPhoneId = phone.startsWith("store_") ? phone : `store_${phone}`;
+
+    if (!user.phoneId) {
+      ElMessage.error("用户信息不完整");
+      return;
+    }
+
+    await cancelFollewed({
+      followedId: user.phoneId,
+      fansId: currentUserPhoneId
+    });
+
+    // 更新关注状态
+    user.isFollowed = 0;
+    user.isFollowThis = 0;
+
+    ElMessage.success("已取消关注");
+  } catch (error: any) {
+    if (error !== "cancel") {
+      console.error("取消关注失败:", error);
+      ElMessage.error(error?.message || "取消关注失败,请重试");
+    }
+  }
+};
+
 // 初始化
 onMounted(() => {
   loadUserInfo();
@@ -2115,6 +2340,15 @@ onMounted(() => {
             }
           }
         }
+        .add-friend-btn {
+          display: flex;
+          flex-shrink: 0;
+          align-items: center;
+          margin-left: auto;
+          .btn-icon {
+            margin-right: 4px;
+          }
+        }
       }
     }
     .user-bio {
@@ -2910,6 +3144,99 @@ onMounted(() => {
       }
     }
   }
+
+  // 添加好友对话框样式
+  .add-friend-dialog-content {
+    .search-box {
+      margin-bottom: 20px;
+    }
+    .search-results {
+      max-height: 400px;
+      overflow-y: auto;
+      .search-loading {
+        display: flex;
+        gap: 8px;
+        align-items: center;
+        justify-content: center;
+        padding: 40px 0;
+        color: #909399;
+      }
+      .search-results-count {
+        padding: 0 4px;
+        margin-bottom: 12px;
+        font-size: 14px;
+        color: #909399;
+      }
+      .search-results-list {
+        .search-result-item {
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+          padding: 16px;
+          border-bottom: 1px solid #f0f0f0;
+          transition: background-color 0.2s;
+          &:hover {
+            background-color: #f5f7fa;
+          }
+          &:last-child {
+            border-bottom: none;
+          }
+          .user-info-row {
+            display: flex;
+            flex: 1;
+            gap: 12px;
+            align-items: center;
+            .user-avatar-small {
+              display: flex;
+              flex-shrink: 0;
+              align-items: center;
+              justify-content: center;
+              width: 48px;
+              height: 48px;
+              overflow: hidden;
+              background-color: #f0f0f0;
+              border-radius: 50%;
+              img {
+                width: 100%;
+                height: 100%;
+                object-fit: cover;
+              }
+            }
+            .user-details {
+              flex: 1;
+              min-width: 0;
+              .user-name-text {
+                margin-bottom: 4px;
+                overflow: hidden;
+                font-size: 16px;
+                font-weight: 500;
+                color: #303133;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+              }
+              .user-desc {
+                overflow: hidden;
+                font-size: 14px;
+                color: #909399;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+              }
+            }
+          }
+          .action-button {
+            flex-shrink: 0;
+            margin-left: 12px;
+          }
+        }
+      }
+      .search-empty {
+        padding: 40px 0;
+      }
+    }
+    .search-placeholder {
+      padding: 40px 0;
+    }
+  }
 }
 </style>