v1.12.23 대시보드 간소화 및 멤버 작성 이력 탭 추가
This commit is contained in:
@@ -1,69 +1,37 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
memberId: { type: String, default: '' },
|
||||
recent: { type: Boolean, default: false }
|
||||
const { data, error, refresh } = await useFetch('/admin/api/comments', {
|
||||
query: { pageSize: 5 },
|
||||
default: () => ({ items: [], pagination: { total: 0 } })
|
||||
})
|
||||
const page = ref(1)
|
||||
const query = computed(() => ({
|
||||
...(props.memberId ? { memberId: props.memberId } : {}),
|
||||
page: page.value,
|
||||
pageSize: props.recent ? 5 : 10
|
||||
}))
|
||||
const { data, status, error, refresh } = await useFetch('/admin/api/comments', {
|
||||
query,
|
||||
default: () => ({ items: [], pagination: { page: 1, pageCount: 1, total: 0 } })
|
||||
})
|
||||
watch(() => props.memberId, () => { page.value = 1 })
|
||||
let refreshTimer = null
|
||||
onMounted(() => {
|
||||
if (props.recent) refreshTimer = window.setInterval(() => refresh(), 30000)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
if (refreshTimer) window.clearInterval(refreshTimer)
|
||||
})
|
||||
onMounted(() => { refreshTimer = window.setInterval(() => refresh(), 30000) })
|
||||
onUnmounted(() => { if (refreshTimer) window.clearInterval(refreshTimer) })
|
||||
|
||||
/**
|
||||
* 댓글 작성 시각을 한국어 날짜로 표시한다.
|
||||
* 최근 댓글의 작성 시각을 짧게 표시한다.
|
||||
* @param {string} value - 작성 시각
|
||||
* @returns {string} 표시 날짜
|
||||
* @returns {string} 한국어 날짜·시각
|
||||
*/
|
||||
const formatCreatedAt = (value) => new Intl.DateTimeFormat('ko-KR', {
|
||||
dateStyle: 'medium', timeStyle: 'short', timeZone: 'Asia/Seoul'
|
||||
month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Seoul'
|
||||
}).format(new Date(value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="admin-comment-list rounded-xl border border-line bg-white p-5 md:p-6" :aria-busy="status === 'pending'">
|
||||
<h2 class="admin-comment-list__heading text-lg font-semibold">
|
||||
{{ recent ? '최근 댓글' : '작성한 댓글' }}
|
||||
<span class="text-sm font-normal text-muted">전체 {{ data?.pagination.total || 0 }}개 · 답글 포함</span>
|
||||
</h2>
|
||||
<div v-if="error" class="admin-comment-list__error mt-4 text-sm text-red-700" role="alert">
|
||||
댓글을 불러오지 못했습니다.
|
||||
<button type="button" class="underline" @click="refresh()">다시 시도</button>
|
||||
</div>
|
||||
<p v-else-if="status === 'pending'" class="admin-comment-list__loading py-6 text-sm text-muted">댓글을 불러오는 중입니다.</p>
|
||||
<p v-else-if="!data?.items.length" class="admin-comment-list__empty py-6 text-sm text-muted">작성한 댓글이 없습니다.</p>
|
||||
<ul v-else class="admin-comment-list__items mt-3 divide-y divide-line">
|
||||
<li v-for="comment in data.items" :key="comment.id" class="admin-comment-list__item py-4">
|
||||
<div class="admin-comment-list__meta flex flex-wrap items-center gap-2 text-xs text-muted">
|
||||
<NuxtLink :to="`/admin/members/${comment.userId}`" class="font-semibold hover:underline">{{ comment.username }}</NuxtLink>
|
||||
<time :datetime="comment.createdAt">{{ formatCreatedAt(comment.createdAt) }}</time>
|
||||
<span v-if="comment.parentId">답글</span>
|
||||
<span v-if="comment.status !== 'published'">{{ comment.status === 'pending' ? '승인 대기' : '차단됨' }}</span>
|
||||
</div>
|
||||
<p class="admin-comment-list__body my-2 whitespace-pre-wrap break-words text-sm">{{ comment.body }}</p>
|
||||
<div class="admin-comment-list__post flex flex-wrap items-center gap-3 text-sm">
|
||||
<NuxtLink :to="`/admin/posts/${comment.postId}`" class="min-w-0 break-words font-medium hover:underline">{{ comment.postTitle || '(제목 없음)' }}</NuxtLink>
|
||||
<NuxtLink v-if="['published', 'members'].includes(comment.postStatus)" :to="`/post/${encodeURIComponent(comment.postSlug)}#comments`" target="_blank" rel="noopener noreferrer" class="shrink-0 text-muted underline">게시물 보기</NuxtLink>
|
||||
<span v-else class="text-xs text-muted">미공개 게시물</span>
|
||||
</div>
|
||||
<section class="admin-comment-list border border-line bg-white px-4 py-3">
|
||||
<h2 class="admin-comment-list__heading mb-1 text-xs font-semibold text-muted">최근 댓글 <span class="font-normal">· 전체 {{ data?.pagination.total || 0 }}개</span></h2>
|
||||
<p v-if="error" class="admin-comment-list__error text-xs text-red-700" role="alert">
|
||||
댓글을 불러오지 못했습니다. <button type="button" class="underline" @click="refresh()">다시 시도</button>
|
||||
</p>
|
||||
<p v-else-if="!data?.items.length" class="admin-comment-list__empty py-1 text-xs text-muted">작성한 댓글이 없습니다.</p>
|
||||
<ul v-else class="admin-comment-list__items divide-y divide-line">
|
||||
<li v-for="comment in data.items" :key="comment.id" class="admin-comment-list__item grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-3 gap-y-0.5 py-1.5 text-xs md:grid-cols-[minmax(0,2fr)_7rem_8rem_minmax(0,3fr)]">
|
||||
<NuxtLink :to="`/post/${encodeURIComponent(comment.postSlug)}#comments`" v-if="['published', 'members'].includes(comment.postStatus)" target="_blank" rel="noopener noreferrer" class="admin-comment-list__post truncate font-medium hover:underline" :title="comment.postTitle">{{ comment.postTitle || '(제목 없음)' }}</NuxtLink>
|
||||
<NuxtLink v-else :to="`/admin/posts/${comment.postId}`" class="admin-comment-list__post truncate font-medium hover:underline" :title="comment.postTitle">{{ comment.postTitle || '(제목 없음)' }}</NuxtLink>
|
||||
<NuxtLink :to="`/admin/members/${comment.userId}`" class="admin-comment-list__author truncate text-muted hover:underline" :title="comment.username">{{ comment.username }}</NuxtLink>
|
||||
<time :datetime="comment.createdAt" class="admin-comment-list__time text-muted">{{ formatCreatedAt(comment.createdAt) }}</time>
|
||||
<p class="admin-comment-list__body truncate text-muted" :title="comment.body">{{ comment.body }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
<nav v-if="!recent && data?.pagination.pageCount > 1" class="admin-comment-list__pagination mt-4 flex items-center justify-between gap-3 text-sm" aria-label="댓글 페이지">
|
||||
<button type="button" class="rounded border border-line px-3 py-2 disabled:opacity-40" :disabled="status === 'pending' || data.pagination.page <= 1" @click="page = data.pagination.page - 1">이전</button>
|
||||
<span>{{ data.pagination.page }} / {{ data.pagination.pageCount }} 페이지</span>
|
||||
<button type="button" class="rounded border border-line px-3 py-2 disabled:opacity-40" :disabled="status === 'pending' || data.pagination.page >= data.pagination.pageCount" @click="page = data.pagination.page + 1">다음</button>
|
||||
</nav>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user