384 lines
8.7 KiB
Vue
384 lines
8.7 KiB
Vue
<template>
|
|
<view class="interact-page">
|
|
<!-- 页面加载状态 -->
|
|
<Loading type="page" :loading="pageLoading" />
|
|
|
|
<!-- Tab切换 -->
|
|
<view class="tab-header">
|
|
<view
|
|
class="tab-item"
|
|
:class="{ active: activeTab === 'unlockedMe' }"
|
|
@click="switchTab('unlockedMe')"
|
|
>
|
|
<text>解锁我</text>
|
|
</view>
|
|
<view
|
|
class="tab-item"
|
|
:class="{ active: activeTab === 'myUnlocked' }"
|
|
@click="switchTab('myUnlocked')"
|
|
>
|
|
<text>我解锁的</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 用户列表 -->
|
|
<view class="user-list" v-if="list.length > 0">
|
|
<view
|
|
class="user-item"
|
|
v-for="item in list"
|
|
:key="item.id"
|
|
@click="handleUserClick(item.userId)"
|
|
>
|
|
<!-- 头像 -->
|
|
<view class="user-avatar">
|
|
<image
|
|
class="avatar-image"
|
|
:src="item.avatar || defaultAvatar"
|
|
mode="aspectFill"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 用户信息 -->
|
|
<view class="user-info">
|
|
<view class="user-header">
|
|
<text class="user-nickname">{{ item.nickname }}</text>
|
|
<view class="user-badges">
|
|
<view v-if="item.isMember" class="badge member-badge">会员</view>
|
|
<view v-if="item.isRealName" class="badge realname-badge">已实名</view>
|
|
</view>
|
|
</view>
|
|
<view class="user-detail">
|
|
<text>{{ item.age }}岁</text>
|
|
<text class="divider">|</text>
|
|
<text>{{ item.workCity }}</text>
|
|
<text class="divider">|</text>
|
|
<text>{{ item.height }}cm</text>
|
|
</view>
|
|
<view class="user-time">
|
|
<text>{{ formatTime(item.createTime) }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 操作按钮 -->
|
|
<view class="user-action" @click.stop="handleContact(item.userId)">
|
|
<text>联系TA</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<Empty
|
|
v-else-if="!listLoading"
|
|
:text="activeTab === 'unlockedMe' ? '暂无人解锁你' : '你还没有解锁别人'"
|
|
buttonText="去相亲"
|
|
buttonUrl="/pages/index/index"
|
|
/>
|
|
|
|
<!-- 加载更多 -->
|
|
<Loading
|
|
type="more"
|
|
:loading="listLoading"
|
|
:noMore="noMoreData && list.length > 0"
|
|
/>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, onMounted } from 'vue'
|
|
import { getUnlockedMe, getMyUnlocked } from '@/api/interact.js'
|
|
import { formatTimestamp } from '@/utils/format.js'
|
|
import { useUserStore } from '@/store/user.js'
|
|
import Loading from '@/components/Loading/index.vue'
|
|
import Empty from '@/components/Empty/index.vue'
|
|
|
|
export default {
|
|
name: 'UnlockedMePage',
|
|
components: {
|
|
Loading,
|
|
Empty
|
|
},
|
|
setup() {
|
|
const userStore = useUserStore()
|
|
|
|
// 页面状态
|
|
const pageLoading = ref(true)
|
|
const listLoading = ref(false)
|
|
const noMoreData = ref(false)
|
|
const activeTab = ref('unlockedMe')
|
|
|
|
// 数据
|
|
const list = ref([])
|
|
const pageIndex = ref(1)
|
|
const pageSize = 20
|
|
|
|
// 默认头像
|
|
const defaultAvatar = '/static/logo.png'
|
|
|
|
// 加载列表
|
|
const loadList = async (refresh = false) => {
|
|
if (refresh) {
|
|
pageIndex.value = 1
|
|
noMoreData.value = false
|
|
}
|
|
|
|
if (noMoreData.value && !refresh) return
|
|
|
|
listLoading.value = true
|
|
try {
|
|
const api = activeTab.value === 'unlockedMe' ? getUnlockedMe : getMyUnlocked
|
|
const res = await api(pageIndex.value, pageSize)
|
|
|
|
if (res && (res.success || res.code === 0)) {
|
|
const newList = res.data?.items || []
|
|
|
|
if (refresh) {
|
|
list.value = newList
|
|
} else {
|
|
list.value = [...list.value, ...newList]
|
|
}
|
|
|
|
// 判断是否还有更多数据
|
|
if (newList.length < pageSize) {
|
|
noMoreData.value = true
|
|
} else {
|
|
pageIndex.value++
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('加载列表失败:', error)
|
|
} finally {
|
|
listLoading.value = false
|
|
}
|
|
}
|
|
|
|
// 初始化页面
|
|
const initPage = async () => {
|
|
pageLoading.value = true
|
|
try {
|
|
await loadList(true)
|
|
} finally {
|
|
pageLoading.value = false
|
|
}
|
|
}
|
|
|
|
// 切换Tab
|
|
const switchTab = (tab) => {
|
|
if (activeTab.value === tab) return
|
|
activeTab.value = tab
|
|
|
|
// 更新导航栏标题
|
|
uni.setNavigationBarTitle({
|
|
title: tab === 'unlockedMe' ? '解锁我' : '我解锁的'
|
|
})
|
|
|
|
// 重新加载数据
|
|
loadList(true)
|
|
}
|
|
|
|
// 格式化时间
|
|
const formatTime = (timestamp) => {
|
|
return formatTimestamp(timestamp)
|
|
}
|
|
|
|
// 点击用户
|
|
const handleUserClick = (userId) => {
|
|
uni.navigateTo({ url: `/pages/profile/detail?userId=${userId}` })
|
|
}
|
|
|
|
// 联系用户
|
|
const handleContact = (userId) => {
|
|
// 检查是否完善资料
|
|
if (!userStore.isProfileCompleted) {
|
|
uni.showModal({
|
|
title: '提示',
|
|
content: '请先完善您的资料,才能联系对方',
|
|
confirmText: '去完善',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
uni.navigateTo({ url: '/pages/profile/edit' })
|
|
}
|
|
}
|
|
})
|
|
return
|
|
}
|
|
|
|
uni.navigateTo({ url: `/pages/chat/index?targetUserId=${userId}` })
|
|
}
|
|
|
|
onMounted(() => {
|
|
initPage()
|
|
})
|
|
|
|
return {
|
|
pageLoading,
|
|
listLoading,
|
|
noMoreData,
|
|
activeTab,
|
|
list,
|
|
defaultAvatar,
|
|
switchTab,
|
|
formatTime,
|
|
handleUserClick,
|
|
handleContact,
|
|
loadList
|
|
}
|
|
},
|
|
// 下拉刷新
|
|
onPullDownRefresh() {
|
|
this.loadList && this.loadList(true).finally(() => {
|
|
uni.stopPullDownRefresh()
|
|
})
|
|
},
|
|
// 触底加载更多
|
|
onReachBottom() {
|
|
if (!this.noMoreData && !this.listLoading) {
|
|
this.loadList && this.loadList()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.interact-page {
|
|
min-height: 100vh;
|
|
background-color: #f8f8f8;
|
|
}
|
|
|
|
// Tab切换
|
|
.tab-header {
|
|
display: flex;
|
|
background-color: #fff;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
.tab-item {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 28rpx 0;
|
|
position: relative;
|
|
|
|
text {
|
|
font-size: 30rpx;
|
|
color: #666;
|
|
}
|
|
|
|
&.active {
|
|
text {
|
|
color: #ff6b6b;
|
|
font-weight: 600;
|
|
}
|
|
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 60rpx;
|
|
height: 4rpx;
|
|
background-color: #ff6b6b;
|
|
border-radius: 2rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 用户列表
|
|
.user-list {
|
|
padding: 0 20rpx;
|
|
|
|
.user-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24rpx;
|
|
background-color: #fff;
|
|
border-radius: 16rpx;
|
|
margin-top: 20rpx;
|
|
|
|
&:active {
|
|
background-color: #f8f8f8;
|
|
}
|
|
|
|
.user-avatar {
|
|
width: 120rpx;
|
|
height: 120rpx;
|
|
margin-right: 24rpx;
|
|
flex-shrink: 0;
|
|
|
|
.avatar-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 16rpx;
|
|
}
|
|
}
|
|
|
|
.user-info {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
|
|
.user-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 8rpx;
|
|
|
|
.user-nickname {
|
|
font-size: 30rpx;
|
|
font-weight: 500;
|
|
color: #333;
|
|
margin-right: 12rpx;
|
|
}
|
|
|
|
.user-badges {
|
|
display: flex;
|
|
gap: 8rpx;
|
|
|
|
.badge {
|
|
padding: 2rpx 8rpx;
|
|
border-radius: 6rpx;
|
|
font-size: 20rpx;
|
|
color: #fff;
|
|
}
|
|
|
|
.member-badge {
|
|
background: linear-gradient(135deg, #ffd700 0%, #ffb800 100%);
|
|
}
|
|
|
|
.realname-badge {
|
|
background: linear-gradient(135deg, #4cd964 0%, #34c759 100%);
|
|
}
|
|
}
|
|
}
|
|
|
|
.user-detail {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
margin-bottom: 8rpx;
|
|
|
|
.divider {
|
|
margin: 0 8rpx;
|
|
color: #ddd;
|
|
}
|
|
}
|
|
|
|
.user-time {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
|
|
.user-action {
|
|
padding: 12rpx 24rpx;
|
|
background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
|
|
border-radius: 30rpx;
|
|
flex-shrink: 0;
|
|
|
|
text {
|
|
font-size: 26rpx;
|
|
color: #fff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|