Skip to content

Commit 23d491c

Browse files
ymh6315431minghao.yang
andauthored
feat: add pagination for community discussions and comments (#1385)
* Draft MR * feat: add pagination for community discussions and comments --------- Co-authored-by: minghao.yang <[email protected]>
1 parent b81a26e commit 23d491c

File tree

5 files changed

+111
-49
lines changed

5 files changed

+111
-49
lines changed

frontend/src/components/community/CommunityPage.vue

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010
@showDiscussionDetail="showDiscussionDetail"
1111
@showNewDiscussion="showNewDiscussion">
1212
</DiscussionCards>
13+
<CsgPagination
14+
v-if="communityActionName === 'list' && cards.length > 0"
15+
class="mt-6"
16+
:perPage="perPage"
17+
:currentPage="currentPage"
18+
:total="totalDiscussions"
19+
@currentChange="getDiscussion"
20+
/>
1321

1422
<NewCommunityDiscussion
1523
v-if="communityActionName === 'new'"
@@ -52,6 +60,7 @@
5260
import useFetchApi from '../../packs/useFetchApi'
5361
import { useRepoTabStore } from '../../stores/RepoTabStore'
5462
import { validateCommunityActionName, ToNotFoundPage } from '../../packs/utils'
63+
import CsgPagination from '../shared/CsgPagination.vue'
5564
5665
const props = defineProps({
5766
repoType: String,
@@ -71,10 +80,20 @@
7180
const currentDiscussionCreateUserId = ref('')
7281
const currentDiscussionTime = ref('')
7382
const currentDiscussionData = ref(null)
83+
84+
const perPage = ref(10)
85+
const currentPage = ref(1)
86+
const totalDiscussions = ref(0)
7487
7588
const isDataLoading = ref(false)
7689
77-
const getDiscussion = async () => {
90+
const getDiscussion = async (childCurrent) => {
91+
if (childCurrent) {
92+
currentPage.value = childCurrent
93+
}
94+
const params = new URLSearchParams()
95+
params.append('per', perPage.value)
96+
params.append('page', currentPage.value)
7897
isDataLoading.value = true
7998
if (!props.repoPath || props.repoPath === '') {
8099
isDataLoading.value = false
@@ -87,9 +106,10 @@
87106
}
88107
89108
try {
90-
const { data, error } = await useFetchApi(discussionCreateEndpoint).json()
109+
const { data, error } = await useFetchApi(`${discussionCreateEndpoint}?${params.toString()}`).json()
91110
if (data.value) {
92111
const discussions = data.value.data.discussions || []
112+
totalDiscussions.value = data.value.total || 0
93113
cards.value = discussions.sort((a, b) => b.id - a.id)
94114
} else {
95115
ElMessage({

frontend/src/components/community/DiscussionDetails.vue

Lines changed: 86 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,65 @@
11
<template>
22
<div class="flex flex-col gap-[16px]">
3-
<div class="flex justify-between items-center">
4-
<div class="flex items-center gap-2">
5-
<div class="text-gray-700 text-md leading-6 font-medium flex items-center gap-2">
6-
<div v-show="!isEdit" class="text-gray-700 text-md leading-6 font-medium flex items-center gap-2">
7-
<div>{{ title }}</div>
8-
<el-tooltip content="Edit title" placement="top">
9-
<div v-if="canEdit" @click="editTitle" class="cursor-pointer">
10-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
11-
<path d="M8.5 1.5H5.5C4.11929 1.5 3 2.61929 3 4V12C3 13.3807 4.11929 14.5 5.5 14.5H10.5C11.8807 14.5 13 13.3807 13 12V9" stroke="#606266" stroke-linecap="round" stroke-linejoin="round"/>
12-
<path d="M12.5 2.5L13.5 3.5L6.5 10.5H5.5V9.5L12.5 2.5Z" stroke="#606266" stroke-linecap="round" stroke-linejoin="round"/>
13-
</svg>
14-
</div>
15-
</el-tooltip>
16-
</div>
17-
<div v-show="isEdit" class="text-gray-700 text-md leading-6 font-medium flex items-center gap-2">
18-
<input type="text"
19-
ref="inputTitle"
20-
v-model="theTitle"
21-
@change="saveTitle"
22-
@blur="isEdit=false">
23-
</div>
24-
<div class="text-gray-500 flex gap-2 text-sm leading-5">
25-
<a :href="`/profile/${userName}`" class="hover:text-brand-600 hover:underline cursor-pointer">{{userName}}</a>
26-
<div>·</div>
27-
<a>{{ time }}</a>
3+
<template v-if="!isDataLoading">
4+
<div class="flex justify-between items-center">
5+
<div class="flex items-center gap-2">
6+
<div class="text-gray-700 text-md leading-6 font-medium flex items-center gap-2">
7+
<div v-show="!isEdit" class="text-gray-700 text-md leading-6 font-medium flex items-center gap-2">
8+
<div>{{ title }}</div>
9+
<el-tooltip content="Edit title" placement="top">
10+
<div v-if="canEdit" @click="editTitle" class="cursor-pointer">
11+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
12+
<path d="M8.5 1.5H5.5C4.11929 1.5 3 2.61929 3 4V12C3 13.3807 4.11929 14.5 5.5 14.5H10.5C11.8807 14.5 13 13.3807 13 12V9" stroke="#606266" stroke-linecap="round" stroke-linejoin="round"/>
13+
<path d="M12.5 2.5L13.5 3.5L6.5 10.5H5.5V9.5L12.5 2.5Z" stroke="#606266" stroke-linecap="round" stroke-linejoin="round"/>
14+
</svg>
15+
</div>
16+
</el-tooltip>
17+
</div>
18+
<div v-show="isEdit" class="text-gray-700 text-md leading-6 font-medium flex items-center gap-2">
19+
<input type="text"
20+
ref="inputTitle"
21+
v-model="theTitle"
22+
@change="saveTitle"
23+
@blur="isEdit=false">
24+
</div>
25+
<div class="text-gray-500 flex gap-2 text-sm leading-5">
26+
<a :href="`/profile/${userName}`" class="hover:text-brand-600 hover:underline cursor-pointer">{{userName}}</a>
27+
<div>·</div>
28+
<a>{{ time }}</a>
29+
</div>
2830
</div>
2931
</div>
3032
</div>
31-
</div>
32-
33-
<!-- 评论列表 -->
34-
<div class="border border-gray-200 border-b-0.5 rounded-lg" v-for="comment in commentData" :key="comment.id">
35-
<div class="flex justify-between gap-1 border-b rounded-t-lg border-gray-200 items-center px-3 py-2 bg-gray-100">
36-
<div class="flex items-center gap-2 text-md leading-5 text-gray-700 font-normal">
37-
<el-avatar :size="24" :src="comment.user.avatar"></el-avatar>
38-
<div class="flex items-center gap-1">
39-
<a :href="`/profile/${comment.user.name}`" class="hover:text-brand-600 hover:underline cursor-pointer">{{comment.user.name}}</a>
40-
<div>·</div>
41-
<el-tooltip
42-
:content="formatFullTime(comment.created_at)"
43-
placement="top">
44-
<div class="cursor-help">{{formatTime(comment.created_at)}}</div>
45-
</el-tooltip>
33+
<!-- 评论列表 -->
34+
<div class="border border-gray-200 border-b-0.5 rounded-lg" v-for="comment in commentData" :key="comment.id">
35+
<div class="flex justify-between gap-1 border-b rounded-t-lg border-gray-200 items-center px-3 py-2 bg-gray-100">
36+
<div class="flex items-center gap-2 text-md leading-5 text-gray-700 font-normal">
37+
<el-avatar :size="24" :src="comment.user.avatar"></el-avatar>
38+
<div class="flex items-center gap-1">
39+
<a :href="`/profile/${comment.user.name}`" class="hover:text-brand-600 hover:underline cursor-pointer">{{comment.user.name}}</a>
40+
<div>·</div>
41+
<el-tooltip
42+
:content="formatFullTime(comment.created_at)"
43+
placement="top">
44+
<div class="cursor-help">{{formatTime(comment.created_at)}}</div>
45+
</el-tooltip>
46+
</div>
4647
</div>
4748
</div>
49+
<div class="px-3 py-3 rounded-b-lg text-gray-700 text-md font-normal markdown-body" v-html="renderMarkdown(comment.content)"></div>
4850
</div>
49-
<div class="px-3 py-3 rounded-b-lg text-gray-700 text-md font-normal markdown-body" v-html="renderMarkdown(comment.content)"></div>
50-
</div>
51+
</template>
52+
<LoadingSpinner
53+
:loading="isDataLoading"
54+
:text="$t('repo.loadingComments')"
55+
/>
56+
<CsgPagination
57+
class="mt-4"
58+
:perPage="perPage"
59+
:currentPage="currentPage"
60+
:total="totalComments"
61+
@currentChange="handlePageChange"
62+
/>
5163

5264
<!-- 评论输入框 -->
5365
<CommunityMDTextarea ref="mdTextarea" :desc="desc" @inputChange="handleInputChange"></CommunityMDTextarea>
@@ -68,6 +80,8 @@
6880
</template>
6981

7082
<script>
83+
import CsgPagination from '../shared/CsgPagination.vue'
84+
import LoadingSpinner from '../shared/LoadingSpinner.vue'
7185
import CommunityTimeLine from './CommunityTimeLine.vue'
7286
import CommunityMDTextarea from './CommunityMDTextarea.vue'
7387
import { format } from 'timeago.js'
@@ -88,7 +102,9 @@ export default {
88102
},
89103
components: {
90104
CommunityTimeLine,
91-
CommunityMDTextarea
105+
CommunityMDTextarea,
106+
CsgPagination,
107+
LoadingSpinner
92108
},
93109
data() {
94110
return {
@@ -102,7 +118,11 @@ export default {
102118
timelineData: [{ name: 'Username', type: 'change status', state: 'closed', date: '2022-01-01', text: 'Event 1' },
103119
{ name: 'Username', type: 'change status', state: 'open', date: '2023-03-15', text: 'Event 2' },
104120
{ name: 'Username', type: 'change title', title_from: 'xxx', title_to: 'xyx', date: '2023-04-10', text: 'Event 3' }],
105-
userStore: useUserStore()
121+
userStore: useUserStore(),
122+
perPage: 10,
123+
currentPage: 1,
124+
totalComments: 0,
125+
isDataLoading: false,
106126
};
107127
},
108128
computed: {
@@ -263,17 +283,36 @@ export default {
263283
this.theTitle = this.oldTitle
264284
}
265285
},
266-
async getComment(discussionId) {
286+
async getComment(discussionId, childCurrent) {
267287
if (!discussionId) {
268288
return
269289
}
270-
const commentCreateEndpoint = `/discussions/${discussionId}/comments`
290+
if (childCurrent) {
291+
this.currentPage = childCurrent
292+
}
293+
this.isDataLoading = true
294+
const params = new URLSearchParams()
295+
params.append('per', this.perPage)
296+
params.append('page', this.currentPage)
297+
const commentCreateEndpoint = `/discussions/${discussionId}/comments?${params.toString()}`
271298
const {data, error} = await useFetchApi(commentCreateEndpoint).json()
272299
if (data.value) {
273-
this.commentData = data.value.data
300+
this.commentData = data.value.data || []
301+
this.totalComments = data.value.total || 0
274302
} else {
275303
ElMessage.warning(error.value?.msg || '获取评论失败')
276304
}
305+
this.isDataLoading = false
306+
this.scrollToTop()
307+
},
308+
309+
scrollToTop() {
310+
window.scrollTo({ top: 0, behavior: 'smooth' })
311+
},
312+
313+
handlePageChange(page) {
314+
this.currentPage = page
315+
this.getComment(this.discussionId, page)
277316
},
278317
async createComment(discussionId) {
279318
if (!discussionId) {

frontend/src/locales/en_js/repo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const repo = {
22
loading: 'Loading repository information...',
33
loadingCommunity: 'Loading discussion list...',
4+
loadingComments: 'Loading comments...',
45
edit: {
56
fileName: "File Name",
67
main: "Directly submit to the main branch",

frontend/src/locales/zh_hant_js/repo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const repo = {
22
loading: '正在載入倉庫資訊...',
33
loadingCommunity: '正在載入討論列表...',
4+
loadingComments: '正在載入評論...',
45
edit: {
56
fileName: "檔案名稱",
67
main: "直接提交到 main 分支",

frontend/src/locales/zh_js/repo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const repo = {
22
loading: '正在加载仓库信息...',
33
loadingCommunity: '正在加载讨论列表...',
4+
loadingComments: '正在加载评论...',
45
edit: {
56
fileName: "文件名",
67
main: "直接提交到 main 分支",

0 commit comments

Comments
 (0)