Files
sb-front/src/views/board/MyBoardView.vue
T

210 lines
5.2 KiB
Vue
Raw Normal View History

<script setup>
import { onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { boardApi } from '@/api/boardApi'
import { formatRelative } from '@/utils/datetime'
import { boardLabel } from '@/constants/boards'
const router = useRouter()
const tab = ref('posts') // posts | comments
const items = ref([])
const page = ref(1)
const totalPages = ref(0)
const loading = ref(false)
const error = ref(null)
async function load() {
loading.value = true
error.value = null
try {
const res = tab.value === 'posts'
? await boardApi.myPosts({ page: page.value, size: 10 })
: await boardApi.myComments({ page: page.value, size: 10 })
items.value = res.content
totalPages.value = res.totalPages
} catch (e) {
error.value = e.response?.data?.message || '불러오지 못했습니다.'
} finally {
loading.value = false
}
}
function switchTab(t) {
if (tab.value === t) return
tab.value = t
page.value = 1
}
function goPage(p) {
if (p < 1 || p > totalPages.value || p === page.value) return
page.value = p
}
function openPost(category, postId) {
router.push(`/board/${category}/${postId}`)
}
watch([tab, page], load)
onMounted(load)
</script>
<template>
<section class="myboard">
<div class="tabs">
<button type="button" class="tab" :class="{ active: tab === 'posts' }" @click="switchTab('posts')"> </button>
<button type="button" class="tab" :class="{ active: tab === 'comments' }" @click="switchTab('comments')"> 댓글</button>
</div>
<p v-if="error" class="msg error">{{ error }}</p>
<p v-if="loading" class="msg">불러오는 중...</p>
<template v-else>
<ul v-if="items.length" class="list">
<!-- -->
<template v-if="tab === 'posts'">
<li v-for="p in items" :key="p.id" class="item" @click="openPost(p.category, p.id)">
<div class="line1">
<span class="badge">{{ boardLabel(p.category) }}</span>
<span class="title">{{ p.title }}</span>
</div>
<div class="line2">
<span>{{ formatRelative(p.createdAt) }}</span>
<span>· 조회 {{ p.viewCount }}</span>
<span>· 추천 {{ p.upCount || 0 }}</span>
<span v-if="p.commentCount">· 댓글 {{ p.commentCount }}</span>
</div>
</li>
</template>
<!-- 댓글 -->
<template v-else>
<li v-for="c in items" :key="c.id" class="item" @click="openPost(c.category, c.postId)">
<div class="line1">
<span class="badge">{{ boardLabel(c.category) }}</span>
<span class="title">{{ c.postTitle }}</span>
</div>
<div class="comment-text">{{ c.content }}</div>
<div class="line2"><span>{{ formatRelative(c.createdAt) }}</span></div>
</li>
</template>
</ul>
<p v-else class="msg">{{ tab === 'posts' ? '작성한 글이 없습니다.' : '작성한 댓글이 없습니다.' }}</p>
<nav v-if="totalPages > 1" class="pagination">
<button type="button" :disabled="page <= 1" @click="goPage(page - 1)"></button>
<span class="page-info">{{ page }} / {{ totalPages }}</span>
<button type="button" :disabled="page >= totalPages" @click="goPage(page + 1)"></button>
</nav>
</template>
</section>
</template>
<style scoped>
.myboard {
max-width: 800px;
margin: 0 auto;
}
.tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
.tab {
flex: 1;
padding: 0.6rem 0;
border: 1px solid var(--color-border);
border-radius: 8px;
background: var(--color-background-soft);
color: var(--color-text);
cursor: pointer;
font-weight: 600;
}
.tab.active {
border-color: hsla(160, 100%, 37%, 1);
color: hsla(160, 100%, 37%, 1);
background: hsla(160, 100%, 37%, 0.08);
}
.list {
list-style: none;
padding: 0;
margin: 0;
}
.item {
padding: 0.85rem 0.5rem;
border-bottom: 1px solid var(--color-border);
cursor: pointer;
}
.item:hover {
background: var(--color-background-soft);
}
.line1 {
display: flex;
align-items: center;
gap: 0.45rem;
}
.badge {
flex: none;
font-size: 0.7rem;
padding: 0.08rem 0.4rem;
border-radius: 4px;
background: var(--color-background-mute);
color: var(--color-text);
opacity: 0.8;
}
.title {
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.comment-text {
margin-top: 0.3rem;
font-size: 0.9rem;
opacity: 0.85;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.line2 {
margin-top: 0.3rem;
font-size: 0.8rem;
opacity: 0.6;
display: flex;
gap: 0.35rem;
flex-wrap: wrap;
}
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-top: 1.25rem;
}
.pagination button {
width: 36px;
height: 36px;
border: 1px solid var(--color-border);
border-radius: 8px;
background: var(--color-background-soft);
color: var(--color-text);
cursor: pointer;
font-size: 1.1rem;
}
.pagination button:disabled {
opacity: 0.4;
cursor: default;
}
.page-info {
font-size: 0.9rem;
}
.msg {
margin: 1.5rem 0;
text-align: center;
opacity: 0.7;
}
.msg.error {
color: #c0392b;
}
</style>