Skip to content

Commit 5f92ab1

Browse files
committed
feat: reply orders
1 parent 15e167e commit 5f92ab1

File tree

2 files changed

+112
-21
lines changed

2 files changed

+112
-21
lines changed

src/components/courses/ReplySection.vue

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,52 @@
33
<v-divider class="mb-2" />
44
<div class="d-flex justify-space-between align-center mb-2">
55
<div class="text-subtitle-2">{{ totalCount }} 条回复</div>
6-
<div class="d-flex" v-if="showAll">
7-
<v-btn
8-
x-small
9-
outlined
10-
class="mr-1"
11-
:color="sortBy === 'latest' ? 'primary' : ''"
12-
@click="changeSort('latest')"
13-
>
14-
最新
15-
</v-btn>
16-
<v-btn
17-
x-small
18-
outlined
19-
:color="sortBy === 'hottest' ? 'primary' : ''"
20-
@click="changeSort('hottest')"
21-
>
22-
最热
23-
</v-btn>
24-
</div>
256
</div>
267

278
<div v-if="loading" class="py-2 d-flex justify-center">
289
<v-progress-circular indeterminate color="primary" size="20" />
2910
</div>
3011

3112
<div v-else>
13+
<!-- 排序和折叠控件 (仅在showAll时显示) -->
14+
<div v-if="showAll" class="d-flex justify-space-between align-center mb-2">
15+
<div class="d-flex gap">
16+
<v-btn
17+
x-small
18+
outlined
19+
class="mr-1"
20+
:color="sortBy === 'latest' ? 'primary' : ''"
21+
@click="changeSortType('latest')"
22+
>
23+
最新
24+
<v-icon right x-small v-show="sortBy === 'latest'">{{ sortDirection === 'desc' ? icons.mdiChevronDown : icons.mdiChevronUp }}</v-icon>
25+
</v-btn>
26+
<v-btn
27+
x-small
28+
outlined
29+
:color="sortBy === 'hottest' ? 'primary' : ''"
30+
@click="changeSortType('hottest')"
31+
>
32+
最热
33+
<v-icon right x-small v-show="sortBy === 'hottest'">{{ sortDirection === 'desc' ? icons.mdiChevronDown : icons.mdiChevronUp }}</v-icon>
34+
</v-btn>
35+
</div>
36+
<v-btn
37+
x-small
38+
text
39+
color="primary"
40+
@click="collapseReplies"
41+
>
42+
折叠
43+
</v-btn>
44+
</div>
45+
46+
<!-- 分页信息 (仅在showAll时显示) -->
47+
<div v-if="showAll" class="text-caption grey--text mb-2">
48+
第 {{ currentPage }} 页,共 {{ totalPages }} 页
49+
</div>
3250
<v-card
33-
v-for="reply in replies"
51+
v-for="reply in paginatedReplies"
3452
:key="reply.id"
3553
outlined
3654
class="mb-2 pa-2 reply-card"
@@ -90,6 +108,27 @@
90108
</div>
91109
</v-card>
92110

111+
<!-- 分页导航 (仅在showAll时显示) -->
112+
<div v-if="showAll" class="d-flex justify-center align-center mt-4 gap-2">
113+
<v-btn
114+
x-small
115+
outlined
116+
:disabled="currentPage === 1"
117+
@click="currentPage--"
118+
>
119+
上一页
120+
</v-btn>
121+
<span class="text-caption mx-2">{{ currentPage }} / {{ totalPages }}</span>
122+
<v-btn
123+
x-small
124+
outlined
125+
:disabled="currentPage === totalPages"
126+
@click="currentPage++"
127+
>
128+
下一页
129+
</v-btn>
130+
</div>
131+
93132
<v-btn
94133
v-if="!showAll && totalCount > filteredCount"
95134
text
@@ -157,6 +196,8 @@ import {
157196
mdiThumbDown,
158197
mdiShareVariantOutline,
159198
mdiReplyOutline,
199+
mdiChevronUp,
200+
mdiChevronDown,
160201
} from '@mdi/js';
161202
import AvatarContainer from '@/components/users/profile/AvatarContainer';
162203
import ReplyChainDialog from '@/components/courses/ReplyChainDialog';
@@ -193,7 +234,10 @@ export default {
193234
totalCount: 0,
194235
filteredCount: 0,
195236
sortBy: 'latest',
237+
sortDirection: 'desc',
196238
showAll: false,
239+
currentPage: 1,
240+
pageSize: 10,
197241
replyContent: '',
198242
replyTarget: null,
199243
isAnonymous: false,
@@ -204,16 +248,42 @@ export default {
204248
mdiThumbDown,
205249
mdiShareVariantOutline,
206250
mdiReplyOutline,
251+
mdiChevronUp,
252+
mdiChevronDown,
207253
},
208254
};
209255
},
256+
computed: {
257+
totalPages() {
258+
return Math.ceil(this.replies.length / this.pageSize);
259+
},
260+
paginatedReplies() {
261+
if (!this.showAll) {
262+
return this.replies.slice(0, this.filteredCount);
263+
}
264+
const start = (this.currentPage - 1) * this.pageSize;
265+
const end = start + this.pageSize;
266+
return this.replies.slice(start, end);
267+
},
268+
},
210269
watch: {
211270
commentId: {
212271
immediate: true,
213272
handler() {
214273
this.fetchReplies();
215274
},
216275
},
276+
sortDirection() {
277+
if (this.showAll) {
278+
this.currentPage = 1;
279+
this.replies.reverse();
280+
}
281+
},
282+
showAll: {
283+
handler() {
284+
this.currentPage = 1;
285+
},
286+
},
217287
},
218288
methods: {
219289
unixToReadable,
@@ -279,11 +349,29 @@ export default {
279349
this.sortBy = sortBy;
280350
this.fetchReplies();
281351
},
352+
changeSortType(sortBy) {
353+
if (this.sortBy === sortBy) {
354+
this.sortDirection = this.sortDirection === 'desc' ? 'asc' : 'desc';
355+
return;
356+
}
357+
this.sortBy = sortBy;
358+
this.sortDirection = 'desc';
359+
this.currentPage = 1;
360+
this.fetchReplies();
361+
},
362+
collapseReplies() {
363+
this.showAll = false;
364+
this.totalCount = this.replies.length;
365+
this.replies = this.replies.filter(reply => reply.like >= 5);
366+
this.filteredCount = this.replies.length;
367+
this.currentPage = 1;
368+
},
282369
showAllReplies() {
283370
if (this.showAll) {
284371
return;
285372
}
286373
this.showAll = true;
374+
this.currentPage = 1;
287375
this.fetchReplies();
288376
},
289377
setReplyTarget(reply) {
@@ -392,4 +480,7 @@ export default {
392480
border-left: 3px solid rgba(0, 0, 0, 0.1);
393481
}
394482
}
483+
.gap {
484+
gap: 8px;
485+
}
395486
</style>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
function unixToReadable(unix) {
2-
return new Date(unix * 1000).toISOString().slice(0, 10);
2+
return new Date(unix * 1000).toISOString().slice(0, 19).replace('T', ' ');
33
}
44

55
export { unixToReadable };

0 commit comments

Comments
 (0)