관리자 글 목록 고정 기능 추가
This commit is contained in:
@@ -5,6 +5,7 @@ definePageMeta({
|
||||
|
||||
const deletingId = ref('')
|
||||
const togglingFeaturedId = ref('')
|
||||
const togglingPinnedId = ref('')
|
||||
const openPostMenuId = ref('')
|
||||
const postMenuStyle = ref({})
|
||||
const errorMessage = ref('')
|
||||
@@ -51,7 +52,8 @@ const { data: postsResponse, refresh: refreshPosts } = await useFetch('/admin/ap
|
||||
},
|
||||
counts: {
|
||||
total: 0,
|
||||
featured: 0
|
||||
featured: 0,
|
||||
pinned: 0
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -325,7 +327,8 @@ const postPagination = computed(() => postsResponse.value?.pagination || {
|
||||
/** 관리자 글 목록 통계 정보 */
|
||||
const postCounts = computed(() => postsResponse.value?.counts || {
|
||||
total: 0,
|
||||
featured: 0
|
||||
featured: 0,
|
||||
pinned: 0
|
||||
})
|
||||
|
||||
/** 게시물에 사용 중인 태그 옵션 */
|
||||
@@ -370,6 +373,9 @@ const totalPostCount = computed(() => Number(postCounts.value.total || 0))
|
||||
/** 추천(`isFeatured`) 게시물 수 */
|
||||
const featuredPostCount = computed(() => Number(postCounts.value.featured || 0))
|
||||
|
||||
/** 관리자 목록 상단 고정 게시물 수 */
|
||||
const pinnedPostCount = computed(() => Number(postCounts.value.pinned || 0))
|
||||
|
||||
/** 필터 적용 후 총 게시물 수 */
|
||||
const filteredPostCount = computed(() => Number(postPagination.value.total || 0))
|
||||
|
||||
@@ -790,6 +796,31 @@ const togglePostFeatured = async (post) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 관리자 목록 고정 여부를 토글한다.
|
||||
* @param {Object} post - 게시물
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const togglePostPinned = async (post) => {
|
||||
closePostMenu()
|
||||
togglingPinnedId.value = post.id
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
await $fetch(`/admin/api/posts/${post.id}/pinned`, {
|
||||
method: 'PUT',
|
||||
body: {
|
||||
adminPinned: !post.adminPinned
|
||||
}
|
||||
})
|
||||
await refreshPosts()
|
||||
} catch (error) {
|
||||
errorMessage.value = error?.data?.message || '고정 설정을 변경하지 못했습니다.'
|
||||
} finally {
|
||||
togglingPinnedId.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 삭제
|
||||
* @param {Object} post - 삭제할 게시물
|
||||
@@ -871,6 +902,10 @@ watch(postPageCount, (pageCount) => {
|
||||
<span class="admin-posts__count-separator text-[#c8ced3]"> · </span>
|
||||
<span class="admin-posts__count-featured">추천 {{ featuredPostCount }}개</span>
|
||||
</template>
|
||||
<template v-if="pinnedPostCount > 0">
|
||||
<span class="admin-posts__count-separator text-[#c8ced3]"> · </span>
|
||||
<span class="admin-posts__count-pinned">고정 {{ pinnedPostCount }}개</span>
|
||||
</template>
|
||||
<template v-if="hasActiveListFilters && filteredPostCount !== totalPostCount">
|
||||
<span class="admin-posts__count-separator text-[#c8ced3]"> · </span>
|
||||
<span class="admin-posts__count-filtered">표시 {{ filteredPostCount }}개</span>
|
||||
@@ -1062,6 +1097,12 @@ watch(postPageCount, (pageCount) => {
|
||||
<span class="admin-posts__comment-count text-xs font-medium text-muted">
|
||||
댓글 {{ post.commentCount || 0 }}
|
||||
</span>
|
||||
<span
|
||||
v-if="post.adminPinned"
|
||||
class="admin-posts__pinned-badge inline-flex h-5 items-center rounded bg-[#15171a] px-1.5 text-[10px] font-semibold text-white"
|
||||
>
|
||||
고정
|
||||
</span>
|
||||
</div>
|
||||
<div class="admin-posts__slug-row mt-1 flex items-center gap-1 text-xs text-muted">
|
||||
<span class="admin-posts__slug truncate">/post/{{ post.slug }}</span>
|
||||
@@ -1133,14 +1174,14 @@ watch(postPageCount, (pageCount) => {
|
||||
:ref="(element) => setPostMenuTriggerRef(post.id, element)"
|
||||
class="admin-posts__row-menu-trigger inline-flex size-9 items-center justify-center rounded text-[#394047] transition-colors hover:bg-[#eceff2] focus-visible:outline focus-visible:ring-2 focus-visible:ring-[#8e9cac] focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-40"
|
||||
type="button"
|
||||
:disabled="deletingId === post.id || togglingFeaturedId === post.id"
|
||||
:disabled="deletingId === post.id || togglingFeaturedId === post.id || togglingPinnedId === post.id"
|
||||
:aria-expanded="openPostMenuId === post.id"
|
||||
aria-haspopup="menu"
|
||||
:aria-label="openPostMenuId === post.id ? '게시글 메뉴 닫기' : '게시글 메뉴'"
|
||||
@click.stop="togglePostMenu(post.id)"
|
||||
>
|
||||
<span
|
||||
v-if="deletingId === post.id || togglingFeaturedId === post.id"
|
||||
v-if="deletingId === post.id || togglingFeaturedId === post.id || togglingPinnedId === post.id"
|
||||
class="text-[10px] font-semibold text-muted"
|
||||
aria-hidden="true"
|
||||
>…</span>
|
||||
@@ -1163,6 +1204,15 @@ watch(postPageCount, (pageCount) => {
|
||||
role="menu"
|
||||
data-admin-post-row-menu
|
||||
>
|
||||
<button
|
||||
class="admin-posts__row-menu-item block w-full px-4 py-2.5 text-left hover:bg-[#f3f5f7] disabled:opacity-50"
|
||||
type="button"
|
||||
role="menuitem"
|
||||
:disabled="togglingPinnedId === post.id"
|
||||
@click="togglePostPinned(post)"
|
||||
>
|
||||
{{ post.adminPinned ? '고정 해제' : '상단 고정' }}
|
||||
</button>
|
||||
<button
|
||||
class="admin-posts__row-menu-item block w-full px-4 py-2.5 text-left hover:bg-[#f3f5f7] disabled:opacity-50"
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user