필터 날짜 및 페이지 개수 100개 추가

This commit is contained in:
nevermoregb 2025-03-18 15:48:45 +09:00
parent 701497a0b0
commit dfb2a3e57e

View File

@ -6,18 +6,19 @@
<div class="mb-3 w-100"> <div class="mb-3 w-100">
<search-bar @update:data="search" @keyup.enter="searchOnEnter" class="flex-grow-1" /> <search-bar @update:data="search" @keyup.enter="searchOnEnter" class="flex-grow-1" />
</div> </div>
<div class="d-flex align-items-center" style="gap: 15px;"> <div class="d-flex align-items-center" style="gap: 15px">
<!-- 리스트 갯수 선택 --> <!-- 리스트 갯수 선택 -->
<select class="form-select w-auto" v-model="selectedSize" @change="handleSizeChange" style="margin-left: 0;"> <select class="form-select w-auto" v-model="selectedSize" @change="handleSizeChange" style="margin-left: 0">
<option value="10">10개씩</option> <option value="10">10개씩</option>
<option value="20">20개씩</option> <option value="20">20개씩</option>
<option value="30">30개씩</option> <option value="30">30개씩</option>
<option value="50">50개씩</option> <option value="50">50개씩</option>
<option value="100">100개씩</option>
</select> </select>
<!-- 셀렉트 박스 --> <!-- 셀렉트 박스 -->
<select class="form-select w-auto" v-model="selectedOrder" @change="handleSortChange"> <select class="form-select w-auto" v-model="selectedOrder" @change="handleSortChange">
<option value="date">최신날짜</option> <option value="date">날짜</option>
<option value="views">조회수</option> <option value="views">조회수</option>
</select> </select>
@ -38,26 +39,33 @@
<table class="datatables-users table border-top dataTable dtr-column"> <table class="datatables-users table border-top dataTable dtr-column">
<thead> <thead>
<tr> <tr>
<th style="width: 11%;" class="text-center fw-bold">번호</th> <th style="width: 11%" class="text-center fw-bold">번호</th>
<th style="width: 45%;" class="text-center fw-bold">제목</th> <th style="width: 45%" class="text-center fw-bold">제목</th>
<th style="width: 10%;" class="text-center fw-bold">작성자</th> <th style="width: 10%" class="text-center fw-bold">작성자</th>
<th style="width: 15%;" class="text-center fw-bold">작성일</th> <th style="width: 15%" class="text-center fw-bold">작성일</th>
<th style="width: 9%;" class="text-center fw-bold">조회수</th> <th style="width: 9%" class="text-center fw-bold">조회수</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<!-- 공지사항 --> <!-- 공지사항 -->
<template v-if="pagination.currentPage === 1 && !showNotices"> <template v-if="pagination.currentPage === 1 && !showNotices">
<tr v-for="(notice, index) in noticeList" <tr
v-for="(notice, index) in noticeList"
:key="'notice-' + index" :key="'notice-' + index"
class="bg-label-gray fw-bold" class="bg-label-gray fw-bold"
@click="goDetail(notice.id)"> @click="goDetail(notice.id)"
>
<td class="text-center">공지</td> <td class="text-center">공지</td>
<td class="cursor-pointer"> <td class="cursor-pointer">
📌 {{ notice.title }} 📌 {{ notice.title }}
<span v-if="notice.commentCount" class="text-danger fw-bold me-1">[ {{ notice.commentCount }} ]</span> <span v-if="notice.commentCount" class="text-danger fw-bold me-1"
>[ {{ notice.commentCount }} ]</span
>
<i v-if="notice.img" class="bi bi-image me-1 align-middle"></i> <i v-if="notice.img" class="bi bi-image me-1 align-middle"></i>
<i v-if="Array.isArray(notice.hasAttachment) && notice.hasAttachment.length > 0" class="bi bi-paperclip"></i> <i
v-if="Array.isArray(notice.hasAttachment) && notice.hasAttachment.length > 0"
class="bi bi-paperclip"
></i>
<span v-if="isNewPost(notice.rawDate)" class="badge bg-danger text-white ms-2 fs-tiny">N</span> <span v-if="isNewPost(notice.rawDate)" class="badge bg-danger text-white ms-2 fs-tiny">N</span>
</td> </td>
<td class="text-center">{{ notice.author }}</td> <td class="text-center">{{ notice.author }}</td>
@ -66,16 +74,21 @@
</tr> </tr>
</template> </template>
<!-- 일반 게시물 --> <!-- 일반 게시물 -->
<tr v-for="(post, index) in generalList" <tr
v-for="(post, index) in generalList"
:key="'post-' + index" :key="'post-' + index"
class="invert-bg-white" class="invert-bg-white"
@click="goDetail(post.realId)"> @click="goDetail(post.realId)"
>
<td class="text-center">{{ post.id }}</td> <td class="text-center">{{ post.id }}</td>
<td class="cursor-pointer"> <td class="cursor-pointer">
{{ post.title }} {{ post.title }}
<span v-if="post.commentCount" class="comment-count">[ {{ post.commentCount }} ]</span> <span v-if="post.commentCount" class="comment-count">[ {{ post.commentCount }} ]</span>
<i v-if="post.img" class="bi bi-image me-1"></i> <i v-if="post.img" class="bi bi-image me-1"></i>
<i v-if="Array.isArray(post.hasAttachment) && post.hasAttachment.length > 0" class="bi bi-paperclip"></i> <i
v-if="Array.isArray(post.hasAttachment) && post.hasAttachment.length > 0"
class="bi bi-paperclip"
></i>
<span v-if="isNewPost(post.rawDate)" class="badge bg-danger text-white ms-2 fs-tiny">N</span> <span v-if="isNewPost(post.rawDate)" class="badge bg-danger text-white ms-2 fs-tiny">N</span>
</td> </td>
<td class="text-center">{{ post.author }}</td> <td class="text-center">{{ post.author }}</td>
@ -86,9 +99,7 @@
</table> </table>
<!-- 게시물이 없을 --> <!-- 게시물이 없을 -->
<div v-if="generalList.length === 0"> <div v-if="generalList.length === 0">
<p class="text-center pt-10 mt-2 mb-0 text-muted"> <p class="text-center pt-10 mt-2 mb-0 text-muted">게시물이 없습니다.</p>
게시물이 없습니다.
</p>
</div> </div>
</div> </div>
</div> </div>
@ -96,11 +107,7 @@
<!-- 페이지네이션 --> <!-- 페이지네이션 -->
<div class="row g-3"> <div class="row g-3">
<div class="mt-8"> <div class="mt-8">
<Pagination <Pagination v-if="pagination.pages" v-bind="pagination" @update:currentPage="handlePageChange" />
v-if="pagination.pages"
v-bind="pagination"
@update:currentPage="handlePageChange"
/>
</div> </div>
</div> </div>
</div> </div>
@ -109,30 +116,29 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import Pagination from '@c/pagination/Pagination.vue'; import Pagination from '@c/pagination/Pagination.vue';
import SearchBar from '@c/search/SearchBar.vue'; import SearchBar from '@c/search/SearchBar.vue';
import router from '@/router'; import router from '@/router';
import WriteButton from '@c/button/WriteBtn.vue'; import WriteButton from '@c/button/WriteBtn.vue';
import axios from '@api'; import axios from '@api';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import isToday from 'dayjs/plugin/isToday'; import isToday from 'dayjs/plugin/isToday';
import isYesterday from 'dayjs/plugin/isYesterday'; import isYesterday from 'dayjs/plugin/isYesterday';
import 'bootstrap-icons/font/bootstrap-icons.css'; import 'bootstrap-icons/font/bootstrap-icons.css';
dayjs.extend(isToday);
dayjs.extend(isYesterday);
dayjs.extend(isToday); //
dayjs.extend(isYesterday); const generalList = ref([]);
const noticeList = ref([]);
const searchText = ref('');
const selectedOrder = ref('date');
const selectedSize = ref(10);
const showNotices = ref(false);
// const pagination = ref({
const generalList = ref([]);
const noticeList = ref([]);
const searchText = ref('');
const selectedOrder = ref('date');
const selectedSize = ref(10);
const showNotices = ref(false);
const pagination = ref({
currentPage: 1, currentPage: 1,
pages: 1, pages: 1,
prePage: 0, prePage: 0,
@ -144,59 +150,59 @@ const pagination = ref({
navigatePages: 10, navigatePages: 10,
navigatepageNums: [1], navigatepageNums: [1],
navigateFirstPage: 1, navigateFirstPage: 1,
navigateLastPage: 1 navigateLastPage: 1,
}); });
// //
const goDetail = (id) => { const goDetail = id => {
router.push({ name: 'BoardDetail', params: { id: id } }); router.push({ name: 'BoardDetail', params: { id: id } });
}; };
// ( HH:mm, YYYY-MM-DD) // ( HH:mm, YYYY-MM-DD)
const formatDate = (dateString) => { const formatDate = dateString => {
const date = dayjs(dateString); const date = dayjs(dateString);
return date.isToday() ? date.format('HH:mm') : date.format('YYYY-MM-DD'); return date.isToday() ? date.format('HH:mm') : date.format('YYYY-MM-DD');
}; };
// ( ) // ( )
const isNewPost = (dateString) => { const isNewPost = dateString => {
const date = dayjs(dateString); const date = dayjs(dateString);
return date.isToday() || date.isYesterday(); return date.isToday() || date.isYesterday();
}; };
// //
const search = (e) => { const search = e => {
searchText.value = e.trim(); searchText.value = e.trim();
fetchGeneralPosts(1); fetchGeneralPosts(1);
}; };
// //
const handleSortChange = () => { const handleSortChange = () => {
fetchGeneralPosts(1); fetchGeneralPosts(1);
}; };
// //
const handleSizeChange = () => { const handleSizeChange = () => {
fetchGeneralPosts(1); fetchGeneralPosts(1);
}; };
// //
const fetchGeneralPosts = async (page = 1) => { const fetchGeneralPosts = async (page = 1) => {
try { try {
const { data } = await axios.get("board/general", { const { data } = await axios.get('board/general', {
params: { params: {
page, page,
size: selectedSize.value, size: selectedSize.value,
orderBy: selectedOrder.value, orderBy: selectedOrder.value,
searchKeyword: searchText.value searchKeyword: searchText.value,
} },
}); });
if (data?.data) { if (data?.data) {
const totalPosts = data.data.total; const totalPosts = data.data.total;
generalList.value = data.data.list.map((post, index) => ({ generalList.value = data.data.list.map((post, index) => ({
realId: post.id, realId: post.id,
id: totalPosts - ((page - 1) * selectedSize.value) - index, id: totalPosts - (page - 1) * selectedSize.value - index,
title: post.title, title: post.title,
author: post.author || '익명', author: post.author || '익명',
rawDate: post.date, rawDate: post.date,
@ -204,7 +210,7 @@ const fetchGeneralPosts = async (page = 1) => {
views: post.cnt || 0, views: post.cnt || 0,
hasAttachment: post.hasAttachment, hasAttachment: post.hasAttachment,
img: post.firstImageUrl || null, img: post.firstImageUrl || null,
commentCount : post.commentCount commentCount: post.commentCount,
})); }));
pagination.value = { pagination.value = {
@ -220,18 +226,17 @@ const fetchGeneralPosts = async (page = 1) => {
navigatePages: data.data.navigatePages, navigatePages: data.data.navigatePages,
navigatepageNums: data.data.navigatepageNums, navigatepageNums: data.data.navigatepageNums,
navigateFirstPage: data.data.navigateFirstPage, navigateFirstPage: data.data.navigateFirstPage,
navigateLastPage: data.data.navigateLastPage navigateLastPage: data.data.navigateLastPage,
}; };
} }
} catch (error) { } catch (error) {}
} };
};
// //
const fetchNoticePosts = async () => { const fetchNoticePosts = async () => {
try { try {
const { data } = await axios.get("board/notices", { const { data } = await axios.get('board/notices', {
params: { searchKeyword: searchText.value } params: { searchKeyword: searchText.value },
}); });
if (data?.data) { if (data?.data) {
@ -244,15 +249,14 @@ const fetchNoticePosts = async () => {
views: post.cnt || 0, views: post.cnt || 0,
hasAttachment: post.hasAttachment, hasAttachment: post.hasAttachment,
img: post.firstImageUrl || null, img: post.firstImageUrl || null,
commentCount : post.commentCount commentCount: post.commentCount,
})); }));
} }
} catch (error) { } catch (error) {}
} };
};
// Enter // Enter
const searchOnEnter = (event) => { const searchOnEnter = event => {
const searchTextValue = event.target.value.trim(); const searchTextValue = event.target.value.trim();
if (!searchTextValue || searchTextValue[0] === ' ') { if (!searchTextValue || searchTextValue[0] === ' ') {
@ -261,20 +265,20 @@ const searchOnEnter = (event) => {
searchText.value = searchTextValue; searchText.value = searchTextValue;
fetchGeneralPosts(1); fetchGeneralPosts(1);
}; };
// //
const handlePageChange = (page) => { const handlePageChange = page => {
if (page !== pagination.value.currentPage) { if (page !== pagination.value.currentPage) {
fetchGeneralPosts(page); fetchGeneralPosts(page);
} }
}; };
// //
onMounted(() => { onMounted(() => {
fetchNoticePosts(); fetchNoticePosts();
fetchGeneralPosts(); fetchGeneralPosts();
}); });
</script> </script>
<style scoped> <style scoped>