페이지네이션 및 조회수 카드에 추가, 검색 수정

This commit is contained in:
kimdaae328 2025-01-20 16:14:16 +09:00
parent 5400dea491
commit 0fa34fe90c
4 changed files with 231 additions and 90 deletions

View File

@ -24,8 +24,11 @@
<!-- 날짜 -->
<div class="d-flex justify-content-between">
<small class="text-muted">{{ formattedDate }}</small>
<!-- 좋아요와 댓글 -->
<!-- 조회수, 좋아요, 댓글 -->
<div>
<span class="text-muted me-3">
<i class="fa-regular fa-eye"></i> {{ views || 0 }}
</span>
<span class="text-muted me-3">
<i class="bx bx-like"></i> {{ likes || 0 }}
</span>
@ -66,6 +69,10 @@ const props = defineProps({
type: String,
required: true,
},
views: {
type: Number,
default: 0,
},
likes: {
type: Number,
default: 0,

View File

@ -10,6 +10,7 @@
:title="post.title"
:content="post.content"
:date="post.date"
:views="post.views"
:likes="post.likes"
:comments="post.comments"
/>

View File

@ -1,35 +1,126 @@
<template>
<nav aria-label="Page navigation">
<ul class="pagination pagination-rounded justify-content-center">
<!-- <li class="page-item first">
<a class="page-link" href="javascript:void(0);"><i class="tf-icon bx bx-chevrons-left bx-sm"></i></a>
</li> -->
<!-- <li class="page-item prev">
<a class="page-link" href="javascript:void(0);"><i class="tf-icon bx bx-chevron-left bx-sm"></i></a>
</li> -->
<li class="page-item active">
<a class="page-link" href="javascript:void(0);">1</a>
<!-- 페이지 이동 -->
<li
class="page-item first"
@click="emitPageChange(navigateFirstPage)"
:class="{ disabled: isFirstPage }"
>
<a class="page-link" href="javascript:void(0);">
<i class="tf-icon bx bx-chevrons-left bx-sm"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="javascript:void(0);">2</a>
<!-- 이전 페이지 이동 -->
<li
class="page-item prev"
@click="emitPageChange(prePage)"
:class="{ disabled: !hasPreviousPage }"
>
<a class="page-link" href="javascript:void(0);">
<i class="tf-icon bx bx-chevron-left bx-sm"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="javascript:void(0);">3</a>
<!-- 페이지 번호들 -->
<li
v-for="page in navigatepageNums"
:key="page"
:class="['page-item', { active: page === currentPage }]"
@click="emitPageChange(page)"
>
<a class="page-link" href="javascript:void(0);">{{ page }}</a>
</li>
<li class="page-item">
<a class="page-link" href="javascript:void(0);">4</a>
<!-- 다음 페이지 이동 -->
<li
class="page-item next"
@click="emitPageChange(nextPage)"
:class="{ disabled: !hasNextPage }"
>
<a class="page-link" href="javascript:void(0);">
<i class="tf-icon bx bx-chevron-right bx-sm"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="javascript:void(0);">5</a>
</li>
<li class="page-item next">
<a class="page-link" href="javascript:void(0);"><i class="tf-icon bx bx-chevron-right bx-sm"></i></a>
</li>
<li class="page-item last">
<a class="page-link" href="javascript:void(0);"><i class="tf-icon bx bx-chevrons-right bx-sm"></i></a>
<!-- 마지막 페이지 이동 -->
<li
class="page-item last"
@click="emitPageChange(navigateLastPage)"
:class="{ disabled: isLastPage }"
>
<a class="page-link" href="javascript:void(0);">
<i class="tf-icon bx bx-chevrons-right bx-sm"></i>
</a>
</li>
</ul>
</nav>
</template>
</template>
<script setup></script>
<script setup>
import { defineProps, defineEmits } from 'vue';
// Props
const props = defineProps({
currentPage: {
type: Number,
required: true
},
pages: {
type: Number,
required: true
},
prePage: {
type: Number,
required: true
},
nextPage: {
type: Number,
required: true
},
isFirstPage: {
type: Boolean,
required: true
},
isLastPage: {
type: Boolean,
required: true
},
hasPreviousPage: {
type: Boolean,
required: true
},
hasNextPage: {
type: Boolean,
required: true
},
navigatePages: {
type: Number,
required: true
},
navigatepageNums: {
type: Array,
required: true
},
navigateFirstPage: {
type: Number,
required: true
},
navigateLastPage: {
type: Number,
required: true
}
});
//
const emit = defineEmits(['update:currentPage']);
//
const emitPageChange = (page) => {
if (page !== props.currentPage && page >= 1 && page <= props.pages) {
emit('update:currentPage', page);
}
};
</script>

View File

@ -11,10 +11,10 @@
<div class="row">
<!-- 정렬 셀렉트 박스 -->
<div class="col-md-3 mb-4">
<select class="form-select">
<option selected>정렬 기준 선택</option>
<option value="1">조회수</option>
<option value="2">날짜</option>
<select class="form-select" @change="handleSortChange">
<option value="">정렬 선택</option>
<option value="view">조회수</option>
<option value="date">날짜</option>
</select>
</div>
@ -27,22 +27,33 @@
</div>
<!-- 공지사항 게시물 리스트 -->
<div class="row g-3">
<board-card :posts="filteredList2" @click="goDetail" />
<div class="row g-3 mt-8">
<h3>공지사항</h3>
<board-card :posts="noticeList" @click="goDetail" />
</div>
<!-- 일반 게시물 리스트 -->
<div class="row g-3">
<board-card :posts="paginatedList" @click="goDetail" />
<div class="row g-3 mt-8">
<h3>일반게시판</h3>
<board-card :posts="generalList" @click="goDetail" />
</div>
<!-- 페이지네이션 -->
<div class="row g-3">
<div class="mt-8">
<pagination
:current-page="currentPage"
:total-pages="totalPages"
@update:page="changePage"
<Pagination
:currentPage="pagination.currentPage"
:pages="pagination.pages"
:prePage="pagination.prePage"
:nextPage="pagination.nextPage"
:isFirstPage="pagination.isFirstPage"
:isLastPage="pagination.isLastPage"
:hasPreviousPage="pagination.hasPreviousPage"
:hasNextPage="pagination.hasNextPage"
:navigatePages="pagination.navigatePages"
:navigatepageNums="pagination.navigatepageNums"
:navigateFirstPage="pagination.navigateFirstPage"
:navigateLastPage="pagination.navigateLastPage"
@update:currentPage="handlePageChange"
/>
</div>
</div>
@ -62,6 +73,22 @@ import axios from '@api';
const generalList = ref([]);
const noticeList = ref([]);
const searchText = ref('');
const selectedOrder = ref('');
const sortDirection = ref('desc');
const pagination = ref({
currentPage: 1,
pages: 1,
prePage: 0,
nextPage: 1,
isFirstPage: true,
isLastPage: false,
hasPreviousPage: false,
hasNextPage: false,
navigatePages: 10,
navigatepageNums: [1],
navigateFirstPage: 1,
navigateLastPage: 1
});
//
const goDetail = (id) => {
@ -71,86 +98,101 @@ const goDetail = (id) => {
//
const search = (e) => {
searchText.value = e.trim();
fetchGeneralPosts(1);
fetchNoticePosts(searchText.value);
};
// ()
const filteredList = computed(() =>
generalList.value.filter((item) =>
item.title.toLowerCase().includes(searchText.value.toLowerCase())
)
);
// ()
const filteredList2 = computed(() =>
noticeList.value.filter((item) =>
item.title.toLowerCase().includes(searchText.value.toLowerCase())
)
);
//
const currentPage = ref(1); //
const itemsPerPage = 10; //
//
const paginatedList = computed(() => {
const start = (currentPage.value - 1) * itemsPerPage;
const end = start + itemsPerPage;
return filteredList.value.slice(start, end);
});
//
const totalPages = computed(() => {
return Math.ceil(filteredList.value.length / itemsPerPage);
});
//
const changePage = (page) => {
if (page >= 1 && page <= totalPages.value) {
currentPage.value = page;
}
//
const handleSortChange = (event) => {
const value = event.target.value;
if (value === 'view') {
selectedOrder.value = 'view';
sortDirection.value = 'desc';
} else if (value === 'date') {
selectedOrder.value = 'date';
sortDirection.value = 'desc';
} else {
selectedOrder.value = '';
sortDirection.value = 'desc';
};
fetchGeneralPosts(1);
};
// ()
const fetchPosts = async () => {
const response = await axios.get("board/general");
const fetchGeneralPosts = async (page = 1) => {
const response = await axios.get("board/general", {
params: {
page: page,
orderBy: selectedOrder.value,
sortDirection: sortDirection.value,
searchKeyword: searchText.value
}
});
if (response.data && response.data.data && Array.isArray(response.data.data.list)) {
generalList.value = response.data.data.list.map((post, index) => ({
if (response.data && response.data.data) {
const data = response.data.data;
//
generalList.value = data.list.map((post, index) => ({
...post,
id: post.id || index,
img: post.img || null,
likes: post.likes || 0,
comments: post.comments || 0,
views: post.cnt || 0,
likes: post.likeCount || 0,
comments: post.commentCount || 0,
}));
//
pagination.value = {
currentPage: data.pageNum,
pages: data.pages,
prePage: data.prePage,
nextPage: data.nextPage,
isFirstPage: data.isFirstPage,
isLastPage: data.isLastPage,
hasPreviousPage: data.hasPreviousPage,
hasNextPage: data.hasNextPage,
navigatePages: data.navigatePages,
navigatepageNums: data.navigatepageNums,
navigateFirstPage: data.navigateFirstPage,
navigateLastPage: data.navigateLastPage
};
} else {
console.error("데이터 오류:", response.data);
}
};
const fetchPosts2 = async () => {
const response = await axios.get("board/notices");
// ()
const fetchNoticePosts = async () => {
const response = await axios.get("board/notices", {
params: {
searchKeyword: searchText.value
}
});
if (response.data && response.data.data && Array.isArray(response.data.data)) {
noticeList.value = response.data.data.map((post, index) => ({
...post,
id: post.id || index,
img: post.img || null,
likes: post.likes || 0,
comments: post.comments || 0,
views: post.cnt || 0,
likes: post.likeCount || 0,
comments: post.commentCount || 0,
}));
} else {
console.error("데이터 오류:", response.data);
}
};
//
const handlePageChange = (page) => {
if (page !== pagination.value.currentPage) {
fetchGeneralPosts(page);
}
};
//
onMounted(() => {
fetchPosts();
fetchPosts2();
fetchGeneralPosts();
fetchNoticePosts();
});
</script>
<style>
/* 필요에 따라 스타일 추가 */
</style>