Skip to content

Commit 0f0730d

Browse files
authored
Merge pull request #621 from imsyy/dev-list
✨ feat: 列表添加评论
2 parents c0340fa + d91654d commit 0f0730d

14 files changed

Lines changed: 1444 additions & 1825 deletions

File tree

components.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ declare module 'vue' {
3232
HomePageSectionManager: typeof import('./src/components/Modal/HomePageSectionManager.vue')['default']
3333
JumpArtist: typeof import('./src/components/Modal/JumpArtist.vue')['default']
3434
KeyboardSetting: typeof import('./src/components/Setting/KeyboardSetting.vue')['default']
35+
ListComment: typeof import('./src/components/List/ListComment.vue')['default']
36+
ListDetail: typeof import('./src/components/List/ListDetail.vue')['default']
3537
LocalSetting: typeof import('./src/components/Setting/LocalSetting.vue')['default']
3638
Login: typeof import('./src/components/Modal/Login/Login.vue')['default']
3739
LoginCookie: typeof import('./src/components/Modal/Login/LoginCookie.vue')['default']
@@ -134,6 +136,7 @@ declare module 'vue' {
134136
PlayerSlider: typeof import('./src/components/Player/PlayerSlider.vue')['default']
135137
PlayerSpectrum: typeof import('./src/components/Player/PlayerSpectrum.vue')['default']
136138
PlaylistAdd: typeof import('./src/components/Modal/PlaylistAdd.vue')['default']
139+
PlaylistComment: typeof import('./src/components/List/PlaylistComment.vue')['default']
137140
PlaySetting: typeof import('./src/components/Setting/PlaySetting.vue')['default']
138141
Provider: typeof import('./src/components/Global/Provider.vue')['default']
139142
RouterLink: typeof import('vue-router')['RouterLink']
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<!-- 列表评论 -->
2+
<template>
3+
<div ref="commentListRef" class="list-comment">
4+
<div
5+
:style="{ height: height === 'auto' ? 'auto' : `${height || commentListHeight}px` }"
6+
class="comment-container"
7+
>
8+
<n-scrollbar class="comment-scroll">
9+
<div class="comment-content">
10+
<template v-if="commentHotData">
11+
<div class="placeholder">
12+
<div class="title">
13+
<SvgIcon name="Fire" />
14+
<span>热门评论</span>
15+
</div>
16+
</div>
17+
<CommentList
18+
:data="commentHotData"
19+
:loading="commentHotData?.length === 0"
20+
:type="type"
21+
/>
22+
</template>
23+
<div class="placeholder">
24+
<div class="title">
25+
<SvgIcon name="Message" />
26+
<span>全部评论</span>
27+
</div>
28+
</div>
29+
<CommentList
30+
:data="commentData"
31+
:loading="commentLoading"
32+
:type="type"
33+
:load-more="commentHasMore"
34+
@load-more="handleLoadMore"
35+
/>
36+
<div class="placeholder" />
37+
</div>
38+
</n-scrollbar>
39+
</div>
40+
</div>
41+
</template>
42+
43+
<script setup lang="ts">
44+
import type { CommentType } from "@/types/main";
45+
import CommentList from "@/components/List/CommentList.vue";
46+
import { useElementSize } from "@vueuse/core";
47+
import { getComment, getHotComment } from "@/api/comment";
48+
import { formatCommentList } from "@/utils/format";
49+
import { isEmpty } from "lodash-es";
50+
51+
const props = withDefaults(
52+
defineProps<{
53+
// 资源 ID
54+
id: number;
55+
// 评论类型 0: 歌曲, 1: mv, 2: 歌单, 3: 专辑, 4: 电台节目, 5: 视频, 6: 动态, 7: 电台
56+
type: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
57+
// 高度
58+
height?: number | "auto"; // px
59+
}>(),
60+
{},
61+
);
62+
63+
const commentListRef = ref<HTMLElement | null>(null);
64+
65+
// 列表高度
66+
const { height: commentListHeight, stop: stopCalcHeight } = useElementSize(commentListRef);
67+
68+
// 评论数据
69+
const commentLoading = ref<boolean>(false);
70+
const commentData = ref<CommentType[]>([]);
71+
const commentHotData = ref<CommentType[] | null>(null);
72+
const commentPage = ref<number>(1);
73+
const commentHasMore = ref<boolean>(true);
74+
75+
// 获取热门评论
76+
const getHotCommentData = async () => {
77+
if (!props.id) return;
78+
try {
79+
const result = await getHotComment(props.id, props.type);
80+
const formatData = formatCommentList(result.hotComments);
81+
commentHotData.value = formatData?.length > 0 ? formatData : null;
82+
} catch (error) {
83+
console.error("Error getting hot comment data:", error);
84+
commentHotData.value = null;
85+
}
86+
};
87+
88+
// 获取评论数据
89+
const getCommentData = async (clean: boolean = true) => {
90+
if (!props.id) return;
91+
try {
92+
commentLoading.value = true;
93+
if (clean) {
94+
commentData.value = [];
95+
commentPage.value = 1;
96+
commentHasMore.value = true;
97+
}
98+
// 获取热门评论
99+
await getHotCommentData();
100+
// 分页参数
101+
const cursor =
102+
commentPage.value > 1 && commentData.value?.length > 0
103+
? commentData.value[commentData.value.length - 1]?.time
104+
: undefined;
105+
// 获取评论
106+
const result = await getComment(props.id, props.type, commentPage.value, 20, 3, cursor);
107+
if (isEmpty(result.data?.comments)) {
108+
commentHasMore.value = false;
109+
commentLoading.value = false;
110+
return;
111+
}
112+
// 处理数据
113+
const formatData = formatCommentList(result.data.comments);
114+
commentData.value = commentData.value.concat(formatData);
115+
// 是否还有
116+
commentHasMore.value = result.data.hasMore;
117+
commentLoading.value = false;
118+
} catch (error) {
119+
console.error("Error getting comment data:", error);
120+
window.$message.error("获取评论数据失败");
121+
commentLoading.value = false;
122+
}
123+
};
124+
125+
// 加载更多评论
126+
const handleLoadMore = () => {
127+
if (!commentHasMore.value || commentLoading.value) return;
128+
commentPage.value += 1;
129+
getCommentData(false);
130+
};
131+
132+
// 监听 id 变化,重置评论数据
133+
watch(
134+
() => props.id,
135+
(newId) => {
136+
if (newId) {
137+
commentData.value = [];
138+
commentHotData.value = null;
139+
commentPage.value = 1;
140+
commentHasMore.value = true;
141+
getCommentData();
142+
}
143+
},
144+
{ immediate: true },
145+
);
146+
147+
// 如果高度是 auto,停止计算高度
148+
watch(
149+
() => props.height,
150+
(newHeight) => {
151+
if (newHeight === "auto") stopCalcHeight();
152+
},
153+
{ immediate: true },
154+
);
155+
</script>
156+
157+
<style lang="scss" scoped>
158+
.list-comment {
159+
height: 100%;
160+
.title {
161+
display: flex;
162+
align-items: center;
163+
font-size: 18px;
164+
font-weight: bold;
165+
margin-bottom: 12px;
166+
.n-icon {
167+
margin-right: 8px;
168+
font-size: 20px;
169+
}
170+
}
171+
}
172+
</style>

0 commit comments

Comments
 (0)