localhost-front/src/components/main/BoardMain.vue
2025-04-01 09:44:17 +09:00

268 lines
9.9 KiB
Vue

<template>
<div class="row" style="gap: 20px;">
<!-- 공지사항 카드 -->
<div class="col-md-6 col-lg-4 col-xl-4 order-0 mb-6">
<div class="card text-center h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 class="mb-0">공지사항</h3>
<router-link :to="{ name: 'BoardList', query: { type: 'notices' } }" class="btn btn-sm btn-primary">
더보기
</router-link>
</div>
<div class="card-body p-0">
<table class="table mb-0">
<thead>
<tr>
<th class="text-center" style="width: 15%;">번호</th>
<th class="text-center" style="width: 55%;">제목</th>
<th class="text-center" style="width: 15%;">작성일</th>
<th class="text-center" style="width: 15%;">조회수</th>
</tr>
</thead>
<tbody>
<tr
v-for="(post, index) in noticeList"
:key="post.id"
@click="goDetail(post.id, 'notices')"
style="cursor: pointer;"
>
<td class="text-center">{{ index + 1 }}</td>
<td>
{{ post.title }}
<span v-if="post.commentCount" class="text-danger ml-1">[{{ post.commentCount }}]</span>
<span v-if="isNewPost(post.rawDate)" class="badge bg-warning text-dark ml-1">N</span>
</td>
<td class="text-center">{{ post.date }}</td>
<td class="text-center">{{ post.views }}</td>
</tr>
<tr v-if="noticeList.length === 0">
<td colspan="4" class="text-center text-muted">게시물이 없습니다.</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer d-flex justify-content-end">
<router-link :to="{ name: 'BoardList', query: { type: 'notices' } }" class="btn btn-sm btn-primary">
더보기
</router-link>
</div>
</div>
</div>
<!-- 자유게시판 카드 -->
<div class="col-md-6 col-lg-4 col-xl-4 order-0 mb-6">
<div class="card text-center h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 class="mb-0">자유게시판</h3>
<router-link :to="{ name: 'BoardList', query: { type: 'general' } }" class="btn btn-sm btn-primary">
더보기
</router-link>
</div>
<div class="card-body p-0">
<table class="table mb-0">
<thead>
<tr>
<th class="text-center" style="width: 15%;">번호</th>
<th class="text-center" style="width: 55%;">제목</th>
<th class="text-center" style="width: 15%;">작성일</th>
<th class="text-center" style="width: 15%;">조회수</th>
</tr>
</thead>
<tbody>
<tr
v-for="(post, index) in freeList"
:key="post.id"
@click="goDetail(post.id, 'general')"
style="cursor: pointer;"
>
<td class="text-center">{{ index + 1 }}</td>
<td>
{{ post.title }}
<span v-if="post.commentCount" class="text-danger ml-1">[{{ post.commentCount }}]</span>
<span v-if="isNewPost(post.rawDate)" class="badge bg-warning text-dark ml-1">N</span>
</td>
<td class="text-center">{{ post.date }}</td>
<td class="text-center">{{ post.views }}</td>
</tr>
<tr v-if="freeList.length === 0">
<td colspan="4" class="text-center text-muted">게시물이 없습니다.</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer d-flex justify-content-end">
<router-link :to="{ name: 'BoardList', query: { type: 'general' } }" class="btn btn-sm btn-primary">
더보기
</router-link>
</div>
</div>
</div>
<!-- 익명게시판 카드 -->
<div class="col-md-6 col-lg-4 col-xl-4 order-0 mb-6">
<div class="card text-center h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 class="mb-0">익명게시판</h3>
<router-link :to="{ name: 'BoardList', query: { type: 'anonymous' } }" class="btn btn-sm btn-primary">
더보기
</router-link>
</div>
<div class="card-body p-0">
<table class="table mb-0">
<thead>
<tr>
<th class="text-center" style="width: 15%;">번호</th>
<th class="text-center" style="width: 55%;">제목</th>
<th class="text-center" style="width: 15%;">작성일</th>
<th class="text-center" style="width: 15%;">조회수</th>
</tr>
</thead>
<tbody>
<tr
v-for="(post, index) in anonymousList"
:key="post.id"
@click="goDetail(post.id, 'anonymous')"
style="cursor: pointer;"
>
<td class="text-center">{{ index + 1 }}</td>
<td>
{{ post.title }}
<span v-if="post.commentCount" class="text-danger ml-1">[{{ post.commentCount }}]</span>
<span v-if="isNewPost(post.rawDate)" class="badge bg-warning text-dark ml-1">N</span>
</td>
<td class="text-center">{{ post.date }}</td>
<td class="text-center">{{ post.views }}</td>
</tr>
<tr v-if="anonymousList.length === 0">
<td colspan="4" class="text-center text-muted">게시물이 없습니다.</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer d-flex justify-content-end">
<router-link :to="{ name: 'BoardList', query: { type: 'anonymous' } }" class="btn btn-sm btn-primary">
더보기
</router-link>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import axios from '@api';
import dayjs from 'dayjs';
import isToday from 'dayjs/plugin/isToday';
import isYesterday from 'dayjs/plugin/isYesterday';
dayjs.extend(isToday);
dayjs.extend(isYesterday);
const router = useRouter();
// 미리보기 데이터 저장
const noticeList = ref([]);
const freeList = ref([]);
const anonymousList = ref([]);
// 날짜 포맷: 오늘이면 HH:mm, 아니면 YYYY-MM-DD
const formatDate = dateString => {
const date = dayjs(dateString);
return date.isToday() ? date.format('HH:mm') : date.format('YYYY-MM-DD');
};
// 새 게시물 여부: 오늘 또는 어제 작성
const isNewPost = dateString => {
const date = dayjs(dateString);
return date.isToday() || date.isYesterday();
};
// 공지사항 데이터 로드 (최대 5개)
const fetchNoticePosts = async () => {
try {
const { data } = await axios.get('board/notices', { params: { size: 5 } });
if (data?.data) {
noticeList.value = data.data.map(post => ({
id: post.id,
title: post.title,
date: formatDate(post.date),
rawDate: post.date,
views: post.cnt || 0,
commentCount: post.commentCount,
hasAttachment: post.hasAttachment,
img: post.firstImageUrl || null,
}));
}
} catch (error) {
console.error(error);
}
};
// board/general 게시물 로드 후 자유게시판과 익명게시판으로 분리 (최대 10개 조회 후 각각 최대 5개씩)
const fetchGeneralPosts = async () => {
try {
const { data } = await axios.get('board/general', { params: { size: 10 } });
if (data?.data && data.data.list) {
const freePosts = [];
const anonymousPosts = [];
data.data.list.forEach(post => {
// 닉네임이 존재하면 익명게시판, 없으면 자유게시판
if (post.nickname) {
anonymousPosts.push({
id: post.id,
title: post.title,
date: formatDate(post.date),
rawDate: post.date,
views: post.cnt || 0,
commentCount: post.commentCount,
hasAttachment: post.hasAttachment,
img: post.firstImageUrl || null,
});
} else {
freePosts.push({
id: post.id,
title: post.title,
date: formatDate(post.date),
rawDate: post.date,
views: post.cnt || 0,
commentCount: post.commentCount,
hasAttachment: post.hasAttachment,
img: post.firstImageUrl || null,
author: post.author || '익명',
});
}
});
freeList.value = freePosts.slice(0, 5);
anonymousList.value = anonymousPosts.slice(0, 5);
}
} catch (error) {
console.error(error);
}
};
// 상세 페이지 이동 (게시판 타입 전달)
const goDetail = (id, boardType) => {
router.push({ name: 'BoardDetail', params: { id, type: boardType } });
};
onMounted(() => {
fetchNoticePosts();
fetchGeneralPosts();
});
</script>
<style scoped>
.table {
margin-bottom: 0;
}
.badge {
font-size: 0.75rem;
padding: 0.25em 0.5em;
}
.ml-1 {
margin-left: 0.25rem;
}
</style>