Initial commit
This commit is contained in:
4
miniprogram/pages/friends/friends.json
Normal file
4
miniprogram/pages/friends/friends.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationStyle": "custom",
|
||||
"usingComponents": {}
|
||||
}
|
||||
87
miniprogram/pages/friends/friends.ts
Normal file
87
miniprogram/pages/friends/friends.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { UserProfile } from '../../types/index'
|
||||
import { api } from '../../utils/api'
|
||||
import { getAvatarGradient } from '../../utils/format'
|
||||
|
||||
const app = getApp<{ userInfo: any }>()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
tabBarHeight: 56,
|
||||
activeTab: 'following' as 'following' | 'followers',
|
||||
list: [] as any[],
|
||||
followingCount: 0,
|
||||
followersCount: 0,
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
const info = wx.getSystemInfoSync()
|
||||
this.setData({ statusBarHeight: info.statusBarHeight })
|
||||
this.loadList()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
const tabBar = this.getTabBar() as any
|
||||
tabBar?.setSelected?.(2)
|
||||
},
|
||||
|
||||
async loadList() {
|
||||
this.setData({ loading: true })
|
||||
try {
|
||||
const list = await api.getFollowList(this.data.activeTab)
|
||||
const enriched = list.map(u => ({
|
||||
...u,
|
||||
gradient: getAvatarGradient(u._id),
|
||||
isOnline: u.isOnline,
|
||||
}))
|
||||
this.setData({
|
||||
list: enriched,
|
||||
[this.data.activeTab === 'following' ? 'followingCount' : 'followersCount']: list.length,
|
||||
})
|
||||
} catch {
|
||||
wx.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
this.setData({ loading: false, refreshing: false })
|
||||
}
|
||||
},
|
||||
|
||||
switchTab(e: WechatMiniprogram.CustomEvent) {
|
||||
const tab = e.currentTarget.dataset.tab as 'following' | 'followers'
|
||||
if (tab === this.data.activeTab) return
|
||||
this.setData({ activeTab: tab, list: [] })
|
||||
this.loadList()
|
||||
},
|
||||
|
||||
async onFollowTap(e: WechatMiniprogram.CustomEvent) {
|
||||
const uid = e.currentTarget.dataset.uid as string
|
||||
try {
|
||||
await api.followUser(uid)
|
||||
if (this.data.activeTab === 'following') {
|
||||
const list = this.data.list.filter((u: any) => u._id !== uid)
|
||||
this.setData({ list, followingCount: list.length })
|
||||
}
|
||||
} catch {
|
||||
wx.showToast({ title: '操作失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
onItemTap(e: WechatMiniprogram.CustomEvent) {
|
||||
const uid = e.currentTarget.dataset.uid
|
||||
wx.navigateTo({ url: `/pages/pet-detail/pet-detail?userId=${uid}` })
|
||||
},
|
||||
|
||||
onFindFriends() {
|
||||
wx.switchTab({ url: '/pages/nearby/nearby' })
|
||||
},
|
||||
|
||||
onGoNearby() {
|
||||
wx.switchTab({ url: '/pages/nearby/nearby' })
|
||||
},
|
||||
|
||||
async onRefresh() {
|
||||
this.setData({ refreshing: true })
|
||||
await this.loadList()
|
||||
},
|
||||
})
|
||||
66
miniprogram/pages/friends/friends.wxml
Normal file
66
miniprogram/pages/friends/friends.wxml
Normal file
@@ -0,0 +1,66 @@
|
||||
<view class="friends-page">
|
||||
<view class="safe-top" style="height: {{statusBarHeight}}px"></view>
|
||||
|
||||
<view class="topbar">
|
||||
<view class="topbar-logo">汪<text class="logo-accent">友</text></view>
|
||||
<view class="topbar-tabs">
|
||||
<view class="ftab {{activeTab === 'following' ? 'ftab-active' : ''}}" bindtap="switchTab" data-tab="following">
|
||||
关注 <text class="ftab-count">{{followingCount}}</text>
|
||||
</view>
|
||||
<view class="ftab {{activeTab === 'followers' ? 'ftab-active' : ''}}" bindtap="switchTab" data-tab="followers">
|
||||
粉丝 <text class="ftab-count">{{followersCount}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="topbar-btn" bindtap="onFindFriends">+</view>
|
||||
</view>
|
||||
|
||||
<!-- 空态 -->
|
||||
<view wx:if="{{!loading && list.length === 0}}" class="empty-wrap">
|
||||
<view class="empty-inner">
|
||||
<text class="empty-emoji">🐾</text>
|
||||
<text class="empty-title">还没有{{activeTab === 'following' ? '关注' : '粉丝'}}</text>
|
||||
<text class="empty-desc">去附近认识新朋友,一起遛狗打卡吧</text>
|
||||
<view class="btn-primary go-btn" bindtap="onGoNearby">去附近找</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表 -->
|
||||
<scroll-view
|
||||
wx:else
|
||||
scroll-y="true"
|
||||
class="friends-scroll"
|
||||
enhanced="true"
|
||||
show-scrollbar="false"
|
||||
refresher-enabled="true"
|
||||
bindrefresherrefresh="onRefresh"
|
||||
refresher-triggered="{{refreshing}}"
|
||||
>
|
||||
<view
|
||||
wx:for="{{list}}"
|
||||
wx:key="_id"
|
||||
class="friend-item"
|
||||
bindtap="onItemTap"
|
||||
data-uid="{{item._id}}"
|
||||
>
|
||||
<view class="friend-avatar" style="background: {{item.gradient}}">
|
||||
<text>{{item.nickName[0]}}</text>
|
||||
</view>
|
||||
<view class="friend-info">
|
||||
<view class="friend-name-row">
|
||||
<text class="friend-name">{{item.nickName}}</text>
|
||||
<view wx:if="{{item.isOnline}}" class="online-tag">在线</view>
|
||||
</view>
|
||||
<text class="friend-bio">{{item.pets[0] ? item.pets[0].emoji + ' ' + item.pets[0].name + ' · ' + item.pets[0].breed : item.bio || '宠物爱好者'}}</text>
|
||||
</view>
|
||||
<view
|
||||
class="follow-btn {{activeTab === 'following' ? 'following' : ''}}"
|
||||
catchtap="onFollowTap"
|
||||
data-uid="{{item._id}}"
|
||||
>
|
||||
{{activeTab === 'following' ? '已关注' : '关注'}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="height: {{tabBarHeight}}px"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
139
miniprogram/pages/friends/friends.wxss
Normal file
139
miniprogram/pages/friends/friends.wxss
Normal file
@@ -0,0 +1,139 @@
|
||||
.friends-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(180deg, #fff8f2 0%, #f5f0ff 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 28rpx 12rpx;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.topbar-logo { font-size: 44rpx; font-weight: 900; color: #272235; }
|
||||
|
||||
.logo-accent { color: #ff4f91; }
|
||||
|
||||
.topbar-tabs { flex: 1; display: flex; gap: 6rpx; }
|
||||
|
||||
.ftab {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #9b8fa8;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
}
|
||||
|
||||
.ftab-active { color: #ff4f91; background: rgba(255, 79, 145, 0.10); font-weight: 900; }
|
||||
|
||||
.ftab-count { font-size: 22rpx; font-weight: 800; }
|
||||
|
||||
.topbar-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #ff4f91, #ff9f1c);
|
||||
color: #fff;
|
||||
font-size: 40rpx;
|
||||
font-weight: 200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 16rpx rgba(255, 79, 145, 0.28);
|
||||
}
|
||||
|
||||
/* 空态 */
|
||||
.empty-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.empty-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 0 60rpx;
|
||||
}
|
||||
|
||||
.empty-emoji { font-size: 80rpx; }
|
||||
|
||||
.empty-title { font-size: 34rpx; font-weight: 900; color: #272235; }
|
||||
|
||||
.empty-desc { font-size: 26rpx; color: #9b8fa8; text-align: center; line-height: 1.6; }
|
||||
|
||||
.go-btn { margin-top: 20rpx; padding: 22rpx 60rpx; font-size: 28rpx; font-weight: 800; }
|
||||
|
||||
/* 好友列表 */
|
||||
.friends-scroll { flex: 1; }
|
||||
|
||||
.friend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 20rpx 28rpx;
|
||||
background: rgba(255, 255, 255, 0.80);
|
||||
border-bottom: 1rpx solid rgba(43, 37, 61, 0.05);
|
||||
}
|
||||
|
||||
.friend-avatar {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 28rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
color: rgba(39, 34, 53, 0.72);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.friend-info { flex: 1; min-width: 0; }
|
||||
|
||||
.friend-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.friend-name { font-size: 28rpx; font-weight: 800; color: #272235; }
|
||||
|
||||
.online-tag {
|
||||
font-size: 20rpx;
|
||||
font-weight: 800;
|
||||
color: #2fd37a;
|
||||
background: rgba(47, 211, 122, 0.12);
|
||||
border-radius: 999rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
}
|
||||
|
||||
.friend-bio {
|
||||
font-size: 24rpx;
|
||||
color: #9b8fa8;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.follow-btn {
|
||||
background: linear-gradient(135deg, #ff4f91, #ff9f1c);
|
||||
color: #fff;
|
||||
border-radius: 999rpx;
|
||||
padding: 14rpx 28rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 800;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.follow-btn.following {
|
||||
background: rgba(255, 255, 255, 0.80);
|
||||
border: 1rpx solid rgba(43, 37, 61, 0.12);
|
||||
color: #9b8fa8;
|
||||
}
|
||||
Reference in New Issue
Block a user