You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

748 lines
16 KiB

<template>
<view class="follow-tab-container">
<!-- 搜索栏 -->
<view class="search-section">
<view class="search-bar">
<image
class="search-icon"
:src="
showImg('/uploads/20250826/a4d605e82622223c270df0af4e378ab3.png')
"
></image>
<input
class="search-input"
placeholder="搜索已关注的人"
v-model="searchText"
@confirm="handleSearch"
/>
</view>
</view>
<!-- 我的关注标题和排序 -->
<view class="follows-header">
<text class="follows-title">我的关注 ({{ totalCount || 0 }})</text>
<!-- <view class="sort-option" @click="toggleSort">
<text class="sort-text">综合排序</text>
<image class="sort-arrow" :src="showImg('/uploads/20250826/8e40deaa0bc67da3a9b104ff0e6b3e7c.png')"></image>
</view> -->
</view>
<!-- 分类导航 -->
<!-- <view class="category-tabs">
<view
class="tab-item"
:class="{ active: activeCategory === 'all' }"
@click="switchCategory('all')"
>
全部
</view>
<view
class="tab-item"
:class="{ active: activeCategory === 'merchant' }"
@click="switchCategory('merchant')"
>
商家
</view>
</view> -->
<!-- 关注用户列表 -->
<view class="follows-list">
<!-- 加载状态 -->
<view class="loading-state" v-if="loading">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
<!-- 空状态显示 -->
<view class="empty-state" v-else-if="filteredFollowsList.length === 0">
<image
class="empty-icon"
:src="
showImg('/uploads/20250826/a4d605e82622223c270df0af4e378ab3.png')
"
mode="aspectFit"
></image>
<text class="empty-text">{{
searchText ? "未找到相关用户" : "暂无关注"
}}</text>
<text class="empty-desc">{{
searchText ? "换个关键词试试吧" : "关注你感兴趣的人,获取更多精彩内容"
}}</text>
</view>
<view
class="follow-item"
v-for="(item, index) in filteredFollowsList"
:key="item.id"
>
<image
class="user-avatar"
:src="
item.followUserHeadimg ||
'https://epic.js-dyyj.com/uploads/20250728/7d9ba1fe109643681396cb03f60f3218.png'
"
mode="aspectFill"
></image>
<view class="user-info">
<text class="user-name">{{ item.followUserNickname }}</text>
<view class="update-time">
{{ item.formatTime }}
</view>
</view>
<view class="action-buttons">
<view class="follow-status-btn"> 已关注 </view>
<view class="more-options" @click="showOptions(item)">
<text class="more-dots">•••</text>
</view>
</view>
</view>
</view>
<!-- 推荐用户分隔线 -->
<view class="divider-line" v-if="false"></view>
<!-- 推荐用户区域 -->
<view class="recommend-section" v-if="false">
<view class="recommend-header">
<view
class="recommend-title"
style="display: flex; align-items: center"
>
你可能感兴趣的人
<image
style="width: 30rpx; height: 30rpx; margin-left: 10rpx"
:src="
showImg('/uploads/20250826/f1422cbef4c33e8c21d9e7e805c8bad9.png')
"
></image>
</view>
<view class="close-btn" @click="closeRecommend">
<text class="close-text">关闭</text>
</view>
</view>
<view class="recommend-list">
<view
class="recommend-item"
v-for="(item, index) in recommendList"
:key="item.id"
>
<image
class="user-avatar"
src="https://epic.js-dyyj.com/uploads/20250728/7d9ba1fe109643681396cb03f60f3218.png"
mode="aspectFill"
></image>
<view class="user-info">
<text class="user-name">{{ item.name }}</text>
<text class="user-desc">{{ item.description }}</text>
</view>
<view class="action-buttons">
<view class="follow-btn" @click="followUser(item)"> 关注 </view>
<view class="dismiss-btn" @click="dismissUser(item)">
<text class="dismiss-text">×</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "FollowTab",
data() {
return {
searchText: "",
activeCategory: "all",
followsList: [],
recommendList: [
{
id: 101,
name: "颜真卿",
avatar: "/uploads/20250826/avatar1.png",
description: "介绍介绍介绍",
},
{
id: 102,
name: "颜真卿",
avatar: "/uploads/20250826/avatar1.png",
description: "介绍介绍介绍",
},
],
// 分页相关数据
pageNum: 1,
pageSize: 10,
loading: false,
hasMore: true,
totalCount: 0,
};
},
computed: {
filteredFollowsList() {
// 直接返回关注列表,搜索过滤已由后端处理
return this.followsList;
},
},
mounted() {
// 组件挂载时获取关注列表
this.getFollowList();
},
// 监听页面滚动到底部事件
onReachBottom() {
this.loadMoreFollows();
},
// 下拉刷新
onPullDownRefresh() {
this.getFollowList();
},
methods: {
handleSearch() {
// 调用接口进行搜索
this.getFollowList();
},
toggleSort() {
// 切换排序方式
uni.showToast({
title: "排序功能开发中",
icon: "none",
});
},
switchCategory(category) {
this.activeCategory = category;
},
// 获取关注列表数据
getFollowList(refresh = true) {
let token = uni.getStorageSync("token1");
if (!token) {
uni.showToast({
title: "请先登录",
icon: "none",
});
uni.navigateTo({
url: "/pages/login/login",
});
return;
}
if (this.loading) return;
if (refresh) {
this.pageNum = 1;
this.hasMore = true;
}
this.loading = true;
const params = {
pageNum: this.pageNum,
pageSize: this.pageSize,
};
// 如果有搜索文本,添加到请求参数中
if (this.searchText.trim()) {
params.followUserNickname = this.searchText.trim();
}
this.Post(params, "/framework/follow/followList", "DES")
.then((res) => {
if (res.code === 200 && res.rows) {
const newItems = res.rows || [];
if (this.pageNum === 1) {
// 首次加载或刷新
this.followsList = newItems;
this.totalCount = res.total || 0;
} else {
// 加载更多
this.followsList.push(...newItems);
}
// 判断是否还有更多数据
this.hasMore = newItems.length === this.pageSize;
} else {
uni.showToast({
title: res.msg || "获取关注列表失败",
icon: "none",
});
}
})
.catch((error) => {
console.error("获取关注列表失败:", error);
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
})
.finally(() => {
this.loading = false;
uni.stopPullDownRefresh();
});
},
// 加载更多关注数据
loadMoreFollows() {
if (!this.loading && this.hasMore) {
this.pageNum++;
this.getFollowList(false);
}
},
showOptions(item) {
uni.showActionSheet({
itemList: ["取消关注"],
success: (res) => {
switch (res.tapIndex) {
case 0:
this.unfollowUser(item);
break;
case 1:
this.reportUser(item);
break;
case 2:
this.blockUser(item);
break;
}
},
});
},
unfollowUser(item) {
uni.showModal({
title: "提示",
content: "确定要取消关注该用户吗?",
success: (res) => {
if (res.confirm) {
// 调用取消关注接口
this.Post(
{
followUserId: item.followUserId,
type: 2, // 2表示取消关注
},
"/framework/follow/followUser",
"DES"
)
.then((res) => {
if (res.code === 200) {
// 从列表中移除
const index = this.followsList.findIndex(
(user) => user.id === item.id
);
if (index > -1) {
this.followsList.splice(index, 1);
this.totalCount--;
}
uni.showToast({
title: "已取消关注",
icon: "success",
});
} else {
uni.showToast({
title: res.msg || "取消关注失败",
icon: "none",
});
}
})
.catch((error) => {
console.error("取消关注失败:", error);
uni.showToast({
title: "操作失败,请重试",
icon: "none",
});
});
}
},
});
},
reportUser(item) {
uni.showToast({
title: "举报功能开发中",
icon: "none",
});
},
blockUser(item) {
uni.showToast({
title: "拉黑功能开发中",
icon: "none",
});
},
followUser(item) {
// 添加到关注列表
this.followsList.unshift({
id: item.id,
name: item.name,
avatar: item.avatar,
newItems: 0,
category: "user",
});
// 从推荐列表移除
const index = this.recommendList.findIndex((user) => user.id === item.id);
if (index > -1) {
this.recommendList.splice(index, 1);
}
uni.showToast({
title: "关注成功",
icon: "success",
});
},
dismissUser(item) {
const index = this.recommendList.findIndex((user) => user.id === item.id);
if (index > -1) {
this.recommendList.splice(index, 1);
uni.showToast({
title: "已移除推荐",
icon: "success",
});
}
},
closeRecommend() {
this.recommendList = [];
uni.showToast({
title: "已关闭推荐",
icon: "success",
});
},
},
};
</script>
<style lang="scss" scoped>
.follow-tab-container {
background: #fff;
}
/* 搜索栏 */
.search-section {
padding: 32rpx;
background: #fff;
}
.search-bar {
display: flex;
align-items: center;
background: #f8f9fa;
border-radius: 40rpx;
padding: 0 32rpx;
height: 80rpx;
.search-icon {
width: 32rpx;
height: 32rpx;
margin-right: 16rpx;
color: #999;
}
.search-input {
flex: 1;
font-size: 28rpx;
color: #333;
&::placeholder {
color: #999;
}
}
}
/* 关注标题和排序 */
.follows-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20rpx;
padding: 0 32rpx 24rpx;
margin-bottom: 20rpx;
.follows-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.sort-option {
display: flex;
align-items: center;
.sort-text {
font-size: 28rpx;
color: #000000;
margin-right: 8rpx;
}
.sort-arrow {
width: 9rpx;
height: 24rpx;
}
}
}
/* 分类导航 */
.category-tabs {
display: flex;
padding: 0 32rpx 32rpx;
gap: 16rpx;
.tab-item {
border-radius: 32rpx;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
padding: 15rpx 30rpx;
font-size: 28rpx;
color: #000000;
font-weight: bold;
&.active {
background: #00ffff;
color: #000000;
}
}
}
/* 关注用户列表 */
.follows-list {
padding: 0 32rpx;
/* 加载状态样式 */
.loading-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx 0;
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 4rpx solid #f3f3f3;
border-top: 4rpx solid #00ffff;
border-radius: 50%;
margin-bottom: 20rpx;
animation: spin 1s linear infinite;
}
.loading-text {
font-size: 28rpx;
color: #999;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
.empty-icon {
width: 120rpx;
height: 120rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
.empty-text {
font-size: 32rpx;
font-weight: 500;
color: #333;
margin-bottom: 16rpx;
}
.empty-desc {
font-size: 26rpx;
color: #999;
text-align: center;
max-width: 80%;
}
}
.follow-item {
display: flex;
align-items: center;
padding: 32rpx 0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.user-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
margin-right: 24rpx;
}
.user-info {
flex: 1;
.user-name {
display: block;
font-size: 30rpx;
font-weight: 500;
color: #000000;
margin-bottom: 8rpx;
}
.update-tag {
display: inline-block;
background: #f8f9fa;
border-radius: 16rpx;
padding: 10rpx 12rpx;
font-size: 24rpx;
color: #666;
}
.update-time {
font-size: 24rpx;
color: #999;
}
}
.action-buttons {
display: flex;
align-items: center;
gap: 16rpx;
.follow-status-btn {
border-radius: 24rpx;
padding: 12rpx 24rpx;
border: 2rpx solid #e5e5e5;
font-size: 26rpx;
color: #666;
}
.more-options {
padding: 8rpx;
.more-dots {
font-size: 24rpx;
color: #000;
letter-spacing: 2rpx;
}
}
}
}
}
/* 分隔线 */
.divider-line {
height: 1rpx;
background: #f0f0f0;
margin: 32rpx 0;
}
/* 推荐用户区域 */
.recommend-section {
padding: 0 32rpx;
.recommend-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
.recommend-title {
font-size: 28rpx;
font-weight: 500;
color: #666666;
margin-right: 10rpx;
}
.close-btn {
padding: 8rpx 16rpx;
.close-text {
font-size: 28rpx;
color: #666;
}
}
}
.recommend-list {
.recommend-item {
display: flex;
align-items: center;
padding: 32rpx 0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.user-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
margin-right: 24rpx;
}
.user-info {
flex: 1;
.user-name {
display: block;
font-size: 30rpx;
font-weight: 500;
color: #333;
margin-bottom: 8rpx;
}
.user-desc {
font-size: 26rpx;
color: #999;
}
}
.action-buttons {
display: flex;
align-items: center;
gap: 16rpx;
.follow-btn {
border: 2rpx solid #00ffff;
border-radius: 24rpx;
padding: 12rpx 24rpx;
font-size: 26rpx;
color: #000;
font-weight: bold;
}
.dismiss-btn {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background: #f8f9fa;
display: flex;
align-items: center;
justify-content: center;
.dismiss-text {
font-size: 32rpx;
color: #999;
font-weight: 300;
}
}
}
}
}
}
</style>