<template>
|
<view class="container">
|
<!-- 用户信息头部 -->
|
<view class="user-header">
|
<view class="user-avatar-container">
|
<image class="user-avatar" :src="userInfo.avatar" mode="aspectFill"></image>
|
<view class="edit-icon" @click="editProfile" v-if="isSelf">
|
<uni-icons type="compose" size="20" color="#666"></uni-icons>
|
</view>
|
</view>
|
<view class="user-info">
|
<view class="user-name">{{userInfo.nickName}}</view>
|
<view class="user-id">ID: {{userInfo.userId}}</view>
|
<view class="user-desc">{{userInfo.motto || '这个人很懒,什么都没留下~'}}</view>
|
</view>
|
<view class="stats-container">
|
<view class="stat-item" @click="navigateToFollow('fans')">
|
<text class="stat-number">{{userInfo.fansNum}}</text>
|
<text class="stat-label">粉丝</text>
|
</view>
|
<view class="stat-item" @click="navigateToFollow('follow')">
|
<text class="stat-number">{{userInfo.subNum}}</text>
|
<text class="stat-label">关注</text>
|
</view>
|
<view class="stat-item" @click="navigateToLike">
|
<text class="stat-number">{{userInfo.likeNum}}</text>
|
<text class="stat-label">获赞</text>
|
</view>
|
</view>
|
|
<!-- 关注按钮 -->
|
<view class="follow-btn-container" v-if="!userInfo.self">
|
<button
|
class="follow-btn"
|
:class="{followed: userInfo.hasSub}"
|
@click="toggleFollow"
|
>
|
{{userInfo.hasSub ? '取消关注' : '关注'}}
|
</button>
|
</view>
|
</view>
|
|
<!-- 作品/喜欢切换 -->
|
<view class="tab-bar">
|
<view
|
class="tab-item"
|
:class="{active: currentTab === 'works'}"
|
@click="switchTab('works')"
|
>
|
作品
|
</view>
|
<view
|
class="tab-item"
|
:class="{active: currentTab === 'likes'}"
|
@click="switchTab('likes')"
|
>
|
喜欢
|
</view>
|
</view>
|
|
<!-- 视频列表 -->
|
<view class="video-list">
|
<view
|
class="video-item"
|
v-for="(item, index) in videoList"
|
:key="item.id"
|
@click="playVideo(index)"
|
>
|
<image class="video-cover" :src="item.cover" mode="aspectFill"></image>
|
<view class="video-info">
|
<view class="video-stats">
|
<view class="stat">
|
<uni-icons type="heart" size="14" color="#fff"></uni-icons>
|
<text>{{item.collectNum}}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<!-- 空状态 -->
|
<view class="empty-state" v-if="videoList.length === 0">
|
<image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image>
|
<text class="empty-text">{{currentTab === 'works' ? '你还没有发布作品哦~' : '你还没有点赞作品哦~'}}</text>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import {getAuthorInfo, getAuthorVideoPage} from '@/api/user.js'
|
export default {
|
data() {
|
return {
|
currentTab: 'works', // works: 作品, likes: 喜欢
|
authorId: '',
|
userInfo: {
|
avatar: '',
|
nickName: '',
|
userId: '',
|
motto: '',
|
fansNum: 0,
|
subNum: 0,
|
likeNum: 0,
|
self: false,
|
hasSub: false
|
},
|
videoQuery: {
|
authorId: '',
|
pageNumber: 1,
|
pageSize: 10
|
},
|
videoList: []
|
}
|
},
|
onLoad(option) {
|
this.authorId = option.authorId;
|
this.getAuthorInfo();
|
this.getAuthorVideoPage();
|
},
|
methods: {
|
// 获取个人信息
|
async getAuthorInfo() {
|
getAuthorInfo(this.authorId).then(res => {
|
this.userInfo = res.data.data
|
})
|
},
|
async getAuthorVideoPage() {
|
this.videoQuery.authorId = this.authorId;
|
getAuthorVideoPage(this.videoQuery).then(res => {
|
if(this.videoQuery.pageNumber === 1) {
|
this.videoList = res.data.data
|
} else {
|
this.videoList = [
|
...this.videoList,
|
...res.data.data.filter(
|
(newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
|
),
|
];
|
}
|
})
|
},
|
// 获取作品信息
|
// 切换关注状态
|
toggleFollow() {
|
// 模拟请求服务器
|
uni.showLoading({
|
title: '处理中...'
|
});
|
|
setTimeout(() => {
|
this.isFollowed = !this.isFollowed;
|
|
// 更新粉丝数
|
if(this.isFollowed) {
|
this.userInfo.fansCount++;
|
uni.showToast({
|
title: '关注成功',
|
icon: 'success'
|
});
|
} else {
|
this.userInfo.fansCount--;
|
uni.showToast({
|
title: '已取消关注',
|
icon: 'none'
|
});
|
}
|
|
uni.hideLoading();
|
}, 500);
|
},
|
// 切换作品/喜欢tab
|
switchTab(tab) {
|
this.currentTab = tab;
|
// 这里应该根据tab切换请求不同的数据
|
// this.loadVideoList();
|
},
|
|
// 播放视频
|
playVideo(index) {
|
const videoItem = this.videoList[index];
|
uni.navigateTo({
|
url: `/pages/video/play?id=${videoItem.id}`
|
});
|
},
|
|
// 编辑个人资料
|
editProfile() {
|
uni.navigateTo({
|
url: '/pages/user/edit'
|
});
|
},
|
|
// 跳转到粉丝/关注列表
|
navigateToFollow(type) {
|
uni.navigateTo({
|
url: `/pages/user/follow?type=${type}`
|
});
|
},
|
|
// 跳转到点赞列表
|
navigateToLike() {
|
uni.navigateTo({
|
url: '/pages/user/like'
|
});
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.container {
|
padding-bottom: 20rpx;
|
background-color: #f5f5f5;
|
min-height: 100vh;
|
}
|
|
.user-header {
|
background-color: #fff;
|
padding: 30rpx;
|
display: flex;
|
flex-direction: column;
|
position: relative;
|
}
|
|
.user-avatar-container {
|
position: relative;
|
width: 120rpx;
|
height: 120rpx;
|
margin-right: 30rpx;
|
}
|
|
.user-avatar {
|
width: 100%;
|
height: 100%;
|
border-radius: 50%;
|
border: 2rpx solid #f1f1f1;
|
}
|
|
.edit-icon {
|
position: absolute;
|
right: 0;
|
bottom: 0;
|
background-color: #fff;
|
border-radius: 50%;
|
width: 40rpx;
|
height: 40rpx;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
|
}
|
|
.user-info {
|
margin-top: 20rpx;
|
flex: 1;
|
}
|
|
.user-name {
|
font-size: 36rpx;
|
font-weight: bold;
|
margin-bottom: 10rpx;
|
}
|
|
.user-id {
|
font-size: 24rpx;
|
color: #999;
|
margin-bottom: 15rpx;
|
}
|
|
.user-desc {
|
font-size: 28rpx;
|
color: #666;
|
line-height: 1.4;
|
}
|
|
.stats-container {
|
display: flex;
|
margin-top: 30rpx;
|
justify-content: space-around;
|
}
|
|
.stat-item {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
padding: 0 20rpx;
|
}
|
|
.stat-number {
|
font-size: 32rpx;
|
font-weight: bold;
|
margin-bottom: 5rpx;
|
}
|
|
.stat-label {
|
font-size: 24rpx;
|
color: #999;
|
}
|
|
.tab-bar {
|
display: flex;
|
background-color: #fff;
|
margin-bottom: 20rpx;
|
}
|
|
.tab-item {
|
flex: 1;
|
text-align: center;
|
padding: 20rpx 0;
|
font-size: 30rpx;
|
color: #666;
|
position: relative;
|
}
|
|
.tab-item.active {
|
color: #ff2442;
|
font-weight: bold;
|
}
|
|
.tab-item.active::after {
|
content: '';
|
position: absolute;
|
bottom: 0;
|
left: 50%;
|
transform: translateX(-50%);
|
width: 80rpx;
|
height: 4rpx;
|
background-color: #ff2442;
|
border-radius: 2rpx;
|
}
|
|
.video-list {
|
display: flex;
|
flex-wrap: wrap;
|
padding: 0 10rpx;
|
}
|
|
.video-item {
|
width: 50%;
|
padding: 10rpx;
|
box-sizing: border-box;
|
position: relative;
|
}
|
|
.video-cover {
|
width: 100%;
|
height: 350rpx;
|
border-radius: 10rpx;
|
display: block;
|
}
|
|
.video-info {
|
position: absolute;
|
bottom: 20rpx;
|
left: 20rpx;
|
right: 20rpx;
|
color: #fff;
|
font-size: 24rpx;
|
}
|
|
.video-title {
|
display: block;
|
margin-bottom: 10rpx;
|
text-shadow: 0 0 5rpx rgba(0, 0, 0, 0.5);
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
}
|
|
.video-stats {
|
display: flex;
|
}
|
|
.stat {
|
display: flex;
|
align-items: center;
|
margin-right: 20rpx;
|
text-shadow: 0 0 5rpx rgba(0, 0, 0, 0.5);
|
}
|
|
.stat text {
|
margin-left: 5rpx;
|
}
|
|
.empty-state {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 100rpx 0;
|
}
|
|
.empty-image {
|
width: 300rpx;
|
height: 300rpx;
|
opacity: 0.6;
|
margin-bottom: 30rpx;
|
}
|
|
.empty-text {
|
font-size: 28rpx;
|
color: #999;
|
}
|
|
.follow-btn-container {
|
margin-top: 30rpx;
|
padding: 0 20rpx;
|
}
|
|
.follow-btn {
|
background-color: #ff2442;
|
color: #fff;
|
border: none;
|
border-radius: 40rpx;
|
font-size: 28rpx;
|
height: 70rpx;
|
line-height: 70rpx;
|
padding: 0 40rpx;
|
|
&::after {
|
border: none;
|
}
|
|
&.followed {
|
background-color: #f5f5f5;
|
color: #666;
|
}
|
}
|
|
/* 如果是自己的主页,隐藏关注按钮 */
|
.user-header {
|
position: relative;
|
}
|
</style>
|