메인보드
This commit is contained in:
parent
0e901ccaa0
commit
675eb93587
@ -1,267 +1,235 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row" style="gap: 20px;">
|
<div class="row" style="gap: 20px;">
|
||||||
<!-- 공지사항 카드 -->
|
<div class="col-md-6 col-lg-4 col-xl-4 order-0 mb-6">
|
||||||
<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 text-center h-100">
|
<div class="modal-content">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<!-- 모달 본문 -->
|
||||||
<h3 class="mb-0">공지사항</h3>
|
<div class="modal-bod mt-3">
|
||||||
<router-link :to="{ name: 'BoardList', query: { type: 'notices' } }" class="btn btn-sm btn-primary">
|
<!-- 탭 버튼 영역 -->
|
||||||
더보기
|
<div class="btn-group mb-3" role="group">
|
||||||
</router-link>
|
<button
|
||||||
</div>
|
type="button"
|
||||||
<div class="card-body p-0">
|
class="btn"
|
||||||
<table class="table mb-0">
|
:class="selectedBoard === 'notices' ? 'btn-primary' : 'btn-outline-primary'"
|
||||||
<thead>
|
@click="changeBoard('notices')"
|
||||||
|
>
|
||||||
|
공지사항
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn"
|
||||||
|
:class="selectedBoard === 'general' ? 'btn-primary' : 'btn-outline-primary'"
|
||||||
|
@click="changeBoard('general')"
|
||||||
|
>
|
||||||
|
자유게시판
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn"
|
||||||
|
:class="selectedBoard === 'anonymous' ? 'btn-primary' : 'btn-outline-primary'"
|
||||||
|
@click="changeBoard('anonymous')"
|
||||||
|
>
|
||||||
|
익명게시판
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 게시글 미리보기 테이블 -->
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center" style="width: 15%;">번호</th>
|
<!-- 익명게시판은 'nickname', 나머지는 'writer' -->
|
||||||
<th class="text-center" style="width: 55%;">제목</th>
|
<th class="text-center" style="width: 20%;">
|
||||||
<th class="text-center" style="width: 15%;">작성일</th>
|
{{ selectedBoard === 'anonymous' ? 'nickname' : 'writer' }}
|
||||||
<th class="text-center" style="width: 15%;">조회수</th>
|
</th>
|
||||||
|
<!-- 제목 헤더는 왼쪽 정렬 -->
|
||||||
|
<th class="text-start" style="width: 65%;">title</th>
|
||||||
|
<th class="text-center" style="width: 15%;">views</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
v-for="(post, index) in noticeList"
|
v-for="post in currentList"
|
||||||
:key="post.id"
|
:key="post.id"
|
||||||
@click="goDetail(post.id, 'notices')"
|
style="cursor: pointer;"
|
||||||
style="cursor: pointer;"
|
@click="goDetail(post.id, selectedBoard)"
|
||||||
>
|
>
|
||||||
<td class="text-center">{{ index + 1 }}</td>
|
<td class="text-center">
|
||||||
<td>
|
{{ selectedBoard === 'anonymous' ? post.nickname : post.author }}
|
||||||
{{ post.title }}
|
</td>
|
||||||
<span v-if="post.commentCount" class="text-danger ml-1">[{{ post.commentCount }}]</span>
|
<td class="text-start">
|
||||||
<span v-if="isNewPost(post.rawDate)" class="badge bg-warning text-dark ml-1">N</span>
|
<div>
|
||||||
</td>
|
{{ truncateTitle(post.title) }}
|
||||||
<td class="text-center">{{ post.date }}</td>
|
<span v-if="post.commentCount" class="text-danger ml-1">
|
||||||
<td class="text-center">{{ post.views }}</td>
|
[{{ post.commentCount }}]
|
||||||
|
</span>
|
||||||
|
<i v-if="post.img" class="bi bi-image mx-1"></i>
|
||||||
|
<i
|
||||||
|
v-if="post.hasAttachment.length > 0"
|
||||||
|
class="bi bi-paperclip ml-1"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small">
|
||||||
|
{{ post.date }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ post.views }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="noticeList.length === 0">
|
<tr v-if="currentList.length === 0">
|
||||||
<td colspan="4" class="text-center text-muted">게시물이 없습니다.</td>
|
<td colspan="3" class="text-center text-muted">게시물이 없습니다.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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>
|
<!-- 모달 푸터: 더보기 버튼 오른쪽 정렬 -->
|
||||||
|
<div class="modal-foote d-flex">
|
||||||
<!-- 자유게시판 카드 -->
|
<router-link
|
||||||
<div class="col-md-6 col-lg-4 col-xl-4 order-0 mb-6">
|
:to="{ name: 'BoardList', query: { type: selectedBoard } }"
|
||||||
<div class="card text-center h-100">
|
class="btn btn-primary ms-auto"
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
>
|
||||||
<h3 class="mb-0">자유게시판</h3>
|
more
|
||||||
<router-link :to="{ name: 'BoardList', query: { type: 'general' } }" class="btn btn-sm btn-primary">
|
|
||||||
더보기
|
|
||||||
</router-link>
|
</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>
|
|
||||||
|
|
||||||
<!-- 익명게시판 카드 -->
|
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
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';
|
||||||
|
|
||||||
dayjs.extend(isToday);
|
dayjs.extend(isToday);
|
||||||
dayjs.extend(isYesterday);
|
dayjs.extend(isYesterday);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// 미리보기 데이터 저장
|
// 모달이 항상 보이도록 초기값 true
|
||||||
const noticeList = ref([]);
|
const isModalOpen = ref(true);
|
||||||
const freeList = ref([]);
|
|
||||||
const anonymousList = ref([]);
|
|
||||||
|
|
||||||
// 날짜 포맷: 오늘이면 HH:mm, 아니면 YYYY-MM-DD
|
// 현재 선택된 게시판 타입: 'notices', 'general', 'anonymous'
|
||||||
const formatDate = dateString => {
|
const selectedBoard = ref('notices');
|
||||||
const date = dayjs(dateString);
|
|
||||||
return date.isToday() ? date.format('HH:mm') : date.format('YYYY-MM-DD');
|
|
||||||
};
|
|
||||||
|
|
||||||
// 새 게시물 여부: 오늘 또는 어제 작성
|
// 각 게시판 미리보기 데이터 배열
|
||||||
const isNewPost = dateString => {
|
const noticeList = ref([]);
|
||||||
const date = dayjs(dateString);
|
const freeList = ref([]);
|
||||||
return date.isToday() || date.isYesterday();
|
const anonymousList = ref([]);
|
||||||
};
|
|
||||||
|
|
||||||
// 공지사항 데이터 로드 (최대 5개)
|
// 선택된 게시판에 따른 미리보기 목록 computed
|
||||||
const fetchNoticePosts = async () => {
|
const currentList = computed(() => {
|
||||||
try {
|
if (selectedBoard.value === 'notices') return noticeList.value;
|
||||||
const { data } = await axios.get('board/notices', { params: { size: 5 } });
|
if (selectedBoard.value === 'general') return freeList.value;
|
||||||
if (data?.data) {
|
if (selectedBoard.value === 'anonymous') return anonymousList.value;
|
||||||
noticeList.value = data.data.map(post => ({
|
return [];
|
||||||
id: post.id,
|
});
|
||||||
title: post.title,
|
|
||||||
date: formatDate(post.date),
|
// 날짜 포맷 함수: 오늘이면 HH:mm, 아니면 YYYY-MM-DD
|
||||||
rawDate: post.date,
|
const formatDate = dateString => {
|
||||||
views: post.cnt || 0,
|
const date = dayjs(dateString);
|
||||||
commentCount: post.commentCount,
|
return date.isToday() ? date.format('HH:mm') : date.format('YYYY-MM-DD');
|
||||||
hasAttachment: post.hasAttachment,
|
};
|
||||||
img: post.firstImageUrl || null,
|
|
||||||
}));
|
// 제목이 14글자 넘어가면 ... 처리하는 함수
|
||||||
}
|
const truncateTitle = title => {
|
||||||
} catch (error) {
|
return title.length > 10 ? title.slice(0, 10) + '...' : title;
|
||||||
console.error(error);
|
};
|
||||||
|
|
||||||
|
// 공지사항 데이터 로드 (최대 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,
|
||||||
|
img: post.firstImageUrl,
|
||||||
|
author: post.author || '관리자',
|
||||||
|
nickname: post.nickname || '관리자',
|
||||||
|
hasAttachment: post.hasAttachment, // 첨부파일 유무
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
};
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// board/general 게시물 로드 후 자유게시판과 익명게시판으로 분리 (최대 10개 조회 후 각각 최대 5개씩)
|
// board/general 게시글 로드 후 자유게시판과 익명게시판으로 분리 (최대 10개 조회 → 각각 최대 5개)
|
||||||
const fetchGeneralPosts = async () => {
|
const fetchGeneralPosts = async () => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get('board/general', { params: { size: 10 } });
|
const { data } = await axios.get('board/general', { params: { size: 10 } });
|
||||||
if (data?.data && data.data.list) {
|
console.log(data.data.list)
|
||||||
const freePosts = [];
|
if (data?.data && data.data.list) {
|
||||||
const anonymousPosts = [];
|
const freePosts = [];
|
||||||
data.data.list.forEach(post => {
|
const anonymousPosts = [];
|
||||||
// 닉네임이 존재하면 익명게시판, 없으면 자유게시판
|
data.data.list.forEach(post => {
|
||||||
if (post.nickname) {
|
if (post.nickname) {
|
||||||
anonymousPosts.push({
|
// 닉네임이 있으면 익명게시판 데이터
|
||||||
id: post.id,
|
anonymousPosts.push({
|
||||||
title: post.title,
|
id: post.id,
|
||||||
date: formatDate(post.date),
|
title: post.title,
|
||||||
rawDate: post.date,
|
date: formatDate(post.date),
|
||||||
views: post.cnt || 0,
|
img: post.firstImageUrl,
|
||||||
commentCount: post.commentCount,
|
rawDate: post.date,
|
||||||
hasAttachment: post.hasAttachment,
|
views: post.cnt || 0,
|
||||||
img: post.firstImageUrl || null,
|
commentCount: post.commentCount,
|
||||||
});
|
nickname: post.nickname,
|
||||||
} else {
|
hasAttachment: post.hasAttachment, // 첨부파일 유무
|
||||||
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);
|
} else {
|
||||||
anonymousList.value = anonymousPosts.slice(0, 5);
|
// 닉네임이 없으면 자유게시판 데이터
|
||||||
}
|
freePosts.push({
|
||||||
} catch (error) {
|
id: post.id,
|
||||||
console.error(error);
|
title: post.title,
|
||||||
|
date: formatDate(post.date),
|
||||||
|
rawDate: post.date,
|
||||||
|
views: post.cnt || 0,
|
||||||
|
img: post.firstImageUrl,
|
||||||
|
commentCount: post.commentCount,
|
||||||
|
author: post.author || '익명',
|
||||||
|
hasAttachment: post.hasAttachment, // 첨부파일 유무
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
freeList.value = freePosts.slice(0, 5);
|
||||||
|
anonymousList.value = anonymousPosts.slice(0, 5);
|
||||||
}
|
}
|
||||||
};
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 상세 페이지 이동 (게시판 타입 전달)
|
// 탭 변경 함수
|
||||||
const goDetail = (id, boardType) => {
|
const changeBoard = type => {
|
||||||
router.push({ name: 'BoardDetail', params: { id, type: boardType } });
|
selectedBoard.value = type;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
// 상세 페이지 이동 (게시판 타입 전달)
|
||||||
fetchNoticePosts();
|
const goDetail = (id, boardType) => {
|
||||||
fetchGeneralPosts();
|
router.push({ name: 'BoardDetail', params: { id, type: boardType } });
|
||||||
});
|
};
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
// 모달이 열릴 때 데이터 로드
|
||||||
.table {
|
fetchNoticePosts();
|
||||||
margin-bottom: 0;
|
fetchGeneralPosts();
|
||||||
}
|
</script>
|
||||||
.badge {
|
|
||||||
font-size: 0.75rem;
|
<style scoped>
|
||||||
padding: 0.25em 0.5em;
|
.table > :not(caption) > * > * {
|
||||||
}
|
padding: 0 !important;
|
||||||
.ml-1 {
|
}
|
||||||
margin-left: 0.25rem;
|
.badge {
|
||||||
}
|
font-size: 0.75rem;
|
||||||
</style>
|
padding: 0.25em 0.5em;
|
||||||
|
}
|
||||||
|
.ml-1 {
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user