Skip to content

Commit 0c74291

Browse files
committed
feat: 添加所有用户的关注和粉丝列表点击 优化播放排行获取和无权限展示
1 parent 7fa0fa5 commit 0c74291

File tree

8 files changed

+233
-64
lines changed

8 files changed

+233
-64
lines changed

src/i18n/lang/en-US/user.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ export default {
1818
viewPlaylist: 'View Playlist',
1919
noFollowings: 'No Followings',
2020
loadMore: 'Load More',
21-
noSignature: 'This guy is lazy, nothing left'
21+
noSignature: 'This guy is lazy, nothing left',
22+
userFollowsTitle: '\'s Followings',
23+
myFollowsTitle: 'My Followings'
2224
},
2325
follower: {
2426
title: 'Follower List',
2527
noFollowers: 'No Followers',
26-
loadMore: 'Load More'
28+
loadMore: 'Load More',
29+
userFollowersTitle: '\'s Followers',
30+
myFollowersTitle: 'My Followers'
2731
},
2832
detail: {
2933
playlists: 'Playlists',
@@ -32,7 +36,8 @@ export default {
3236
noRecords: 'No Listening History',
3337
artist: 'Artist',
3438
noSignature: 'This guy is lazy, nothing left',
35-
invalidUserId: 'Invalid User ID'
39+
invalidUserId: 'Invalid User ID',
40+
noRecordPermission: '{name} doesn\'t let you see your listening history'
3641
},
3742
message: {
3843
loadFailed: 'Failed to load user page',

src/i18n/lang/zh-CN/user.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ export default {
1818
viewPlaylist: '查看歌单',
1919
noFollowings: '暂无关注',
2020
loadMore: '加载更多',
21-
noSignature: '这个家伙很懒,什么都没留下'
21+
noSignature: '这个家伙很懒,什么都没留下',
22+
userFollowsTitle: '的关注',
23+
myFollowsTitle: '我的关注'
2224
},
2325
follower: {
2426
title: '粉丝列表',
2527
noFollowers: '暂无粉丝',
26-
loadMore: '加载更多'
28+
loadMore: '加载更多',
29+
userFollowersTitle: '的粉丝',
30+
myFollowersTitle: '我的粉丝'
2731
},
2832
detail: {
2933
playlists: '歌单',
@@ -32,7 +36,8 @@ export default {
3236
noRecords: '暂无听歌记录',
3337
artist: '歌手',
3438
noSignature: '这个人很懒,什么都没留下',
35-
invalidUserId: '用户ID无效'
39+
invalidUserId: '用户ID无效',
40+
noRecordPermission: '{name}不让你看听歌排行'
3641
},
3742
message: {
3843
loadFailed: '加载用户页面失败',

src/renderer/api/user.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ export function getUserPlaylist(uid: number, limit: number = 30, offset: number
1414
// 播放历史
1515
// /user/record?uid=32953014&type=1
1616
export function getUserRecord(uid: number, type: number = 0) {
17-
return request.get('/user/record', { params: { uid, type } });
17+
18+
return request.get('/user/record', {
19+
params: { uid, type },
20+
noRetry: true
21+
} as any);
1822
}
1923

2024
// 获取用户关注列表

src/renderer/router/other.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const otherRouter = [
44
name: 'userFollows',
55
meta: {
66
title: '关注列表',
7-
keepAlive: true,
7+
keepAlive: false,
88
showInMenu: false,
99
back: true
1010
},
@@ -15,7 +15,7 @@ const otherRouter = [
1515
name: 'userFollowers',
1616
meta: {
1717
title: '粉丝列表',
18-
keepAlive: true,
18+
keepAlive: false,
1919
showInMenu: false,
2020
back: true
2121
},
@@ -26,7 +26,7 @@ const otherRouter = [
2626
name: 'userDetail',
2727
meta: {
2828
title: '用户详情',
29-
keepAlive: true,
29+
keepAlive: false,
3030
showInMenu: false,
3131
back: true
3232
},

src/renderer/utils/request.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import axios, { InternalAxiosRequestConfig } from 'axios';
22

33
import { useUserStore } from '@/store/modules/user';
44

5-
import { getSetData, isElectron } from '.';
5+
import { getSetData, isElectron, isMobile } from '.';
66

77
let setData: any = null;
88

99
// 扩展请求配置接口
1010
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
1111
retryCount?: number;
12+
noRetry?: boolean;
1213
}
1314

1415
const baseURL = window.electron
@@ -22,7 +23,7 @@ const request = axios.create({
2223
});
2324

2425
// 最大重试次数
25-
const MAX_RETRIES = 3;
26+
const MAX_RETRIES = 1;
2627
// 重试延迟(毫秒)
2728
const RETRY_DELAY = 500;
2829

@@ -42,7 +43,8 @@ request.interceptors.request.use(
4243
// 在get请求params中添加timestamp
4344
config.params = {
4445
...config.params,
45-
timestamp: Date.now()
46+
timestamp: Date.now(),
47+
device: isElectron ? 'pc' : isMobile ? 'mobile' : 'web'
4648
};
4749
const token = localStorage.getItem('token');
4850
if (token && config.method !== 'post') {
@@ -100,7 +102,8 @@ request.interceptors.response.use(
100102
if (
101103
config.retryCount !== undefined &&
102104
config.retryCount < MAX_RETRIES &&
103-
!NO_RETRY_URLS.includes(config.url as string)
105+
!NO_RETRY_URLS.includes(config.url as string) &&
106+
!config.noRetry
104107
) {
105108
config.retryCount++;
106109
console.error(`请求重试第 ${config.retryCount} 次`);

src/renderer/views/user/detail.vue

Lines changed: 104 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
</n-tooltip>
2727
</div>
2828
<div class="user-info-stats">
29-
<div class="user-info-stat-item">
29+
<div class="user-info-stat-item" @click="showFollowerList">
3030
<div class="label">{{ userDetail.profile.followeds }}</div>
3131
<div>{{ t('user.profile.followers') }}</div>
3232
</div>
33-
<div class="user-info-stat-item">
33+
<div class="user-info-stat-item" @click="showFollowList">
3434
<div class="label">{{ userDetail.profile.follows }}</div>
3535
<div>{{ t('user.profile.following') }}</div>
3636
</div>
@@ -50,10 +50,7 @@
5050
<n-tabs type="line" animated>
5151
<!-- 歌单列表 -->
5252
<n-tab-pane name="playlists" :tab="t('user.detail.playlists')">
53-
<div v-if="loading" class="loading-container">
54-
<n-spin size="medium" />
55-
</div>
56-
<div v-else-if="playList.length === 0" class="empty-message">
53+
<div v-if="playList.length === 0" class="empty-message">
5754
{{ t('user.detail.noPlaylists') }}
5855
</div>
5956
<div v-else class="playlist-grid" :class="setAnimationClass('animate__fadeInUp')">
@@ -89,8 +86,11 @@
8986

9087
<!-- 听歌排行 -->
9188
<n-tab-pane name="records" :tab="t('user.detail.records')">
92-
<div v-if="loading" class="loading-container">
93-
<n-spin size="medium" />
89+
<div v-if="!hasRecordPermission" class="empty-message">
90+
<div class="no-permission">
91+
<i class="ri-lock-line text-2xl mr-2"></i>
92+
{{ t('user.detail.noRecordPermission', { name: userDetail.profile.nickname }) }}
93+
</div>
9494
</div>
9595
<div v-else-if="!recordList || recordList.length === 0" class="empty-message">
9696
{{ t('user.detail.noRecords') }}
@@ -103,10 +103,7 @@
103103
:class="setAnimationClass('animate__bounceInUp')"
104104
:style="setAnimationDelay(index, 25)"
105105
>
106-
<div class="play-score">
107-
{{ index + 1 }}
108-
</div>
109-
<song-item class="song-item" :item="item" mini @play="handlePlay" />
106+
<song-item class="song-item" :index="index" :item="item" compact @play="handlePlay" />
110107
</div>
111108
</div>
112109
</n-tab-pane>
@@ -125,7 +122,7 @@
125122

126123
<script lang="ts" setup>
127124
import { useMessage } from 'naive-ui';
128-
import { onMounted, ref } from 'vue';
125+
import { onMounted, ref, watch } from 'vue';
129126
import { useI18n } from 'vue-i18n';
130127
import { useRoute, useRouter } from 'vue-router';
131128
@@ -150,12 +147,12 @@ const playerStore = usePlayerStore();
150147
151148
// 获取路由参数中的用户ID
152149
const userId = ref<number>(Number(route.params.uid));
153-
154150
// 用户数据
155151
const userDetail = ref<IUserDetail>();
156152
const playList = ref<any[]>([]);
157153
const recordList = ref<any[]>([]);
158154
const loading = ref(true);
155+
const hasRecordPermission = ref(true); // 是否有权限查看听歌记录
159156
160157
// 歌单详情相关
161158
const currentList = ref<Playlist>();
@@ -171,34 +168,68 @@ const loadUserData = async () => {
171168
172169
try {
173170
loading.value = true;
171+
recordList.value = []; // 清空之前的记录
172+
hasRecordPermission.value = true; // 重置权限状态
173+
174+
// 分开处理请求,处理可能的错误
175+
// 1. 获取用户详情和歌单列表
176+
try {
177+
const [userDetailRes, playlistRes] = await Promise.all([
178+
getUserDetail(userId.value),
179+
getUserPlaylist(userId.value)
180+
]);
181+
182+
userDetail.value = userDetailRes.data;
183+
playList.value = playlistRes.data.playlist;
184+
} catch (error) {
185+
console.error('加载用户基本信息失败:', error);
186+
message.error(t('user.message.loadBasicInfoFailed'));
187+
return; // 如果基本信息加载失败,直接返回
188+
}
174189
175-
// 使用 Promise.all 并行请求提高效率
176-
const [userDetailRes, playlistRes, recordRes] = await Promise.all([
177-
getUserDetail(userId.value),
178-
getUserPlaylist(userId.value),
179-
getUserRecord(userId.value)
180-
]);
181-
182-
userDetail.value = userDetailRes.data;
183-
playList.value = playlistRes.data.playlist;
184-
185-
if (recordRes.data && recordRes.data.allData) {
186-
recordList.value = recordRes.data.allData.map((item: any) => ({
187-
...item,
188-
...item.song,
189-
picUrl: item.song.al.picUrl
190-
}));
191-
} else {
192-
recordList.value = [];
190+
// 2. 单独处理听歌记录请求,这个请求可能会无权限
191+
try {
192+
const recordRes = await getUserRecord(userId.value);
193+
194+
if (recordRes.data && recordRes.data.allData) {
195+
recordList.value = recordRes.data.allData.map((item: any) => ({
196+
...item,
197+
...item.song,
198+
picUrl: item.song.al.picUrl
199+
}));
200+
}
201+
} catch (error: any) {
202+
console.error('加载听歌记录失败:', error);
203+
// 判断是否是无权限错误
204+
if (error.response?.data?.code === -2 || error.data?.code === -2) {
205+
hasRecordPermission.value = false;
206+
}
207+
// 不显示错误消息,因为这是预期的情况
193208
}
194209
} catch (error) {
195210
console.error('加载用户数据失败:', error);
196-
message.error('加载用户数据失败');
211+
message.error(t('user.message.loadFailed'));
197212
} finally {
198213
loading.value = false;
199214
}
200215
};
201216
217+
// 使用onMounted和watch结合的方式解决路由变化问题
218+
onMounted(() => {
219+
loadUserData();
220+
});
221+
222+
// 监听路由参数变化
223+
watch(
224+
() => route.params.uid,
225+
(newUid) => {
226+
if (newUid && Number(newUid) !== userId.value) {
227+
userId.value = Number(newUid);
228+
loadUserData();
229+
}
230+
}
231+
);
232+
202233
// 替换显示歌单的方法
203234
const openPlaylist = (item: any) => {
204235
listLoading.value = true;
@@ -226,15 +257,36 @@ const handlePlay = () => {
226257
playerStore.setPlayList(tracks);
227258
};
228259
260+
// 显示关注列表
261+
const showFollowList = () => {
262+
if (!userDetail.value) return;
263+
264+
router.push({
265+
path: `/user/follows`,
266+
query: {
267+
uid: userId.value.toString(),
268+
name: userDetail.value.profile.nickname
269+
}
270+
});
271+
};
272+
273+
// 显示粉丝列表
274+
const showFollowerList = () => {
275+
if (!userDetail.value) return;
276+
277+
router.push({
278+
path: `/user/followers`,
279+
query: {
280+
uid: userId.value.toString(),
281+
name: userDetail.value.profile.nickname
282+
}
283+
});
284+
};
285+
229286
// 判断是否为歌手
230287
const isArtist = (profile: any) => {
231288
return profile.userType === 4 || profile.userType === 2 || profile.accountType === 2;
232289
};
233-
234-
// 页面挂载时加载数据
235-
onMounted(() => {
236-
loadUserData();
237-
});
238290
</script>
239291

240292
<style lang="scss" scoped>
@@ -288,6 +340,11 @@ onMounted(() => {
288340
.label {
289341
@apply text-lg font-bold;
290342
}
343+
344+
&:nth-child(1), &:nth-child(2) {
345+
@apply cursor-pointer transition-all duration-200;
346+
@apply hover:bg-black hover:bg-opacity-20 rounded-lg px-2;
347+
}
291348
}
292349
}
293350
@@ -365,5 +422,14 @@ onMounted(() => {
365422
366423
.empty-message {
367424
@apply flex justify-center items-center p-8;
425+
426+
.no-permission {
427+
@apply flex flex-col items-center justify-center text-gray-500 dark:text-gray-400;
428+
@apply p-4 rounded-lg;
429+
430+
i {
431+
@apply text-3xl mb-2;
432+
}
433+
}
368434
}
369435
</style>

0 commit comments

Comments
 (0)