<template>
|
<view class="container">
|
<!-- 用户信息头部 -->
|
<view class="user-header">
|
<view class="user-avatar-container">
|
<image class="user-avatar" :src="userInfo.avatar" mode="aspectFill"></image>
|
</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 class="edit-icon" @click="editInfo" v-if="userInfo.self">
|
<uni-icons type="compose" size="20" color="#666"></uni-icons>编辑主页信息
|
</view>
|
</view>
|
|
<!-- 作品/喜欢切换 -->
|
<view class="tab-bar">
|
<view
|
class="tab-item"
|
:class="{active: currentTab === 'works'}"
|
@click="switchTab('works')"
|
>
|
作品{{`(${videoTotal})`}}
|
</view>
|
<view
|
class="tab-item"
|
:class="{active: currentTab === 'likes'}"
|
@click="switchTab('likes')"
|
>
|
喜欢
|
</view>
|
</view>
|
|
<!-- 视频列表 -->
|
<scroll-view class="video-list" scroll-y :show-scrollbar="false" @scrolltolower="getPage" v-show="currentTab === 'works' && videoList.length > 0">
|
<view
|
class="video-item"
|
v-for="(item, index) in videoList"
|
:key="item.id"
|
>
|
<image class="video-cover" @click="playAuthorVideo(index)" :src="item.coverUrl" mode="aspectFill"></image>
|
<view class="video-info">
|
<view class="video-stats">
|
<view class="stat">
|
<uni-icons type="heart" size="16" color="#fff"></uni-icons>
|
<text>{{item.collectNum}}</text>
|
<view class="more-op">
|
<dropdown-menu
|
:options="item.options"
|
placement="top"
|
theme-color="#07C160"
|
@change="handleChange"
|
></dropdown-menu>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</scroll-view>
|
<scroll-view class="video-list" scroll-y :show-scrollbar="false" @scrolltolower="getPage" v-show="currentTab === 'likes' && collectVideoList.length > 0">
|
<view class="video-container">
|
<view
|
class="video-item"
|
v-for="(item, index) in collectVideoList"
|
:key="item.id"
|
@click="playCollectVideo(index)"
|
>
|
<image class="video-cover" :src="item.coverUrl" mode="aspectFill"></image>
|
<view class="video-info">
|
<view class="video-stats">
|
<view class="stat">
|
<uni-icons type="heart" size="16" color="#fff"></uni-icons>
|
<text>{{item.collectNum}}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</scroll-view>
|
|
<!-- 空状态 -->
|
<view class="empty-state" v-if="videoList.length === 0 && currentTab === 'works'">
|
<!-- <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image> -->
|
<text class="empty-text">还未发布作品哦~</text>
|
</view>
|
<!-- 空状态 -->
|
<view class="empty-state" v-if="collectVideoList.length === 0 && currentTab === 'likes'">
|
<!-- <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image> -->
|
<text class="empty-text">还没有点赞作品哦~</text>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import DropdownMenu from '@/components/dropdown-menu.vue'
|
|
import {getAuthorInfo, getAuthorVideoPage, getAuthorCollectVideoPage} from '@/api/user.js'
|
import {subscribe, unSubscribe} from '@/api/video.js'
|
export default {
|
components: {DropdownMenu},
|
data() {
|
return {
|
options: [
|
{ command: 1, label: '北京' },
|
{ command: 2, label: '上海' },
|
{ command: 3, label: '广州' }
|
],
|
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
|
},
|
collectVideoQuery: {
|
authorId: '',
|
pageNumber: 1,
|
pageSize: 10
|
},
|
videoTotal: 0,
|
videoList: [], // 作品
|
collectVideoList: [], // 收藏
|
nomoreVideo: false,
|
nomoreCollectVideo: false
|
}
|
},
|
onShow() {
|
this.getAuthorInfo();
|
},
|
onLoad(option) {
|
this.authorId = option.authorId;
|
this.getAuthorInfo();
|
this.getAuthorVideoPage();
|
},
|
methods: {
|
handleChange(value) {
|
console.log('选中值:', value)
|
},
|
getPage() {
|
if(this.currentTab === 'works') {
|
if(this.nomoreVideo) {
|
return;
|
}
|
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)
|
),
|
];
|
}
|
if(res.data.data.length < this.videoQuery.pageSize) {
|
this.nomoreVideo = true;
|
} else {
|
this.videoQuery.pageNumber += 1;
|
}
|
})
|
} else if(this.currentTab === 'likes') {
|
if(this.nomoreCollectVideo) {
|
return;
|
}
|
getAuthorCollectVideoPage(this.collectVideoQuery).then(res => {
|
if(this.collectVideoQuery.pageNumber === 1) {
|
this.collectVideoList = res.data.data
|
} else {
|
this.collectVideoList = [
|
...this.collectVideoList,
|
...res.data.data.filter(
|
(newItem) => !this.collectVideoList.some((oldItem) => oldItem.id === newItem.id)
|
),
|
];
|
}
|
if(res.data.data.length < this.collectVideoQuery.pageSize) {
|
this.nomoreCollectVideo = true;
|
} else {
|
this.collectVideoQuery.pageNumber += 1;
|
}
|
})
|
}
|
},
|
// 获取个人信息
|
async getAuthorInfo() {
|
getAuthorInfo(this.authorId).then(res => {
|
this.userInfo = res.data.data
|
})
|
},
|
// 获取作者作品
|
async getAuthorVideoPage() {
|
this.videoQuery.authorId = this.authorId;
|
getAuthorVideoPage(this.videoQuery).then(res => {
|
this.videoList = res.data.data
|
this.videoTotal = res.data.total
|
if(res.data.data.length < this.videoQuery.pageSize) {
|
this.nomoreVideo = true;
|
}
|
})
|
},
|
// 切换关注状态
|
toggleFollow() {
|
if(this.userInfo.hasSub) {
|
// 取消关注
|
unSubscribe(this.authorId).then(res => {
|
uni.showToast({
|
title: '已取消关注',
|
icon: 'none'
|
});
|
this.userInfo.hasSub = false
|
this.userInfo.fansNum -= 1;
|
})
|
} else {
|
// 关注
|
subscribe(this.authorId).then(res => {
|
uni.showToast({
|
title: '关注成功',
|
icon: 'success'
|
});
|
this.userInfo.hasSub = true
|
this.userInfo.fansNum += 1;
|
})
|
}
|
},
|
// 切换作品/喜欢tab
|
switchTab(tab) {
|
if(this.currentTab === tab) {
|
return
|
}
|
this.currentTab = tab;
|
if(tab === 'works') {
|
this.collectVideoList = []
|
this.videoQuery.pageNumber = 1
|
this.getAuthorVideoPage()
|
} else if(tab === 'likes') {
|
this.videoList = []
|
this.collectVideoQuery.pageNumber = 1
|
this.getAuthorCollectVideoPage()
|
}
|
},
|
// 获取作者的收藏视频
|
async getAuthorCollectVideoPage() {
|
this.collectVideoQuery.authorId = this.authorId
|
getAuthorCollectVideoPage(this.collectVideoQuery).then(res => {
|
this.collectVideoList = res.data.data
|
if(res.data.data.length < this.collectVideoQuery.pageSize) {
|
this.nomoreCollectVideo = true;
|
}
|
})
|
},
|
// 播放作者视频
|
playAuthorVideo(index) {
|
const playInfo = {
|
videoList: this.videoList,
|
nomore: this.nomoreVideo,
|
pageNumber: this.videoQuery.pageNumber,
|
playIndex: index
|
}
|
uni.setStorageSync("playInfo", playInfo)
|
uni.navigateTo({
|
url: `/pages/video/video-play?authorId=${this.authorId}&videoFrom=author`
|
});
|
},
|
// 播放收藏视频
|
playAuthorVideo(index) {
|
const playInfo = {
|
videoList: this.collectVideoList,
|
nomore: this.nomoreCollectVideo,
|
pageNumber: this.collectVideoQuery.pageNumber,
|
playIndex: index
|
}
|
uni.setStorageSync("playInfo", playInfo)
|
uni.navigateTo({
|
url: `/pages/video/video-play?authorId=${this.authorId}&videoFrom=collect`
|
});
|
},
|
// 编辑个人资料
|
editInfo() {
|
uni.navigateTo({
|
url: `/pages/video/home-page-edit?authorId=${this.authorId}&avatar=${this.userInfo.avatar}&motto=${this.userInfo.motto || ''}&nickName=${this.userInfo.nickName}`
|
});
|
},
|
|
// 跳转到粉丝/关注列表
|
navigateToFollow(type) {
|
uni.navigateTo({
|
url: `/pages/user/follow?type=${type}`
|
});
|
},
|
|
// 跳转到点赞列表
|
navigateToLike() {
|
uni.navigateTo({
|
url: '/pages/user/like'
|
});
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
body {
|
background-color: #fff !important;
|
}
|
.container {
|
padding-bottom: 20rpx;
|
background-color: white;
|
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: 30rpx;
|
top: 30rpx;
|
background-color: #fff;
|
height: 40rpx;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
}
|
|
.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;
|
padding-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 {
|
width: calc(100% - 20rpx);
|
padding: 0 10rpx;
|
height: calc(100vh - 554rpx);
|
background-color: #fff;
|
}
|
|
.video-item {
|
width: 50%;
|
padding: 10rpx;
|
box-sizing: border-box;
|
position: relative;
|
}
|
|
.video-cover {
|
width: 100%;
|
height: 500rpx;
|
border-radius: 10rpx;
|
display: block;
|
}
|
|
.video-info {
|
display: flex;
|
height: 60rpx;
|
align-items: center;
|
font-size: 24rpx;
|
width: 100%;
|
padding-right: 20rpx;
|
box-sizing: border-box;
|
position: absolute;
|
bottom: 20rpx;
|
}
|
|
.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;
|
width: 100%;
|
}
|
|
.stat {
|
display: flex;
|
width: 100%;
|
align-items: center;
|
position: relative;
|
}
|
|
.more-op {
|
position: absolute;
|
right: 0;
|
}
|
|
.stat text {
|
margin-left: 5rpx;
|
color: #fff;
|
font-size: 14px;
|
}
|
|
.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;
|
}
|
}
|
|
.video-container {
|
display: flex;
|
flex-wrap: wrap
|
}
|
</style>
|