feat: 게시판 공지 UI (관리자) — 작성 체크박스/상세 토글/목록 배지

- BoardWriteView: 관리자가 커뮤니티 새 글 작성 시 '공지로 등록' 체크박스
- BoardDetailView: 관리자 공지 등록/해제 버튼 + 제목 공지 배지
- BoardListView: 공지 배지 + 행 강조(최상단은 백엔드 정렬)
- boardApi: setNotice/unsetNotice

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-27 22:07:03 +09:00
parent ef1d718fb8
commit f07cb349e2
4 changed files with 76 additions and 2 deletions
+24
View File
@@ -2,19 +2,25 @@
import { onMounted, ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { boardApi } from '@/api/boardApi'
import { useAuthStore } from '@/stores/auth'
import MarkdownEditor from '@/components/editor/MarkdownEditor.vue'
import IconBtn from '@/components/ui/IconBtn.vue'
import { DEFAULT_BOARD } from '@/constants/boards'
const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
const category = route.params.category || DEFAULT_BOARD
const editId = route.params.id || null
const isEdit = computed(() => !!editId)
// 공지: 관리자가 커뮤니티 게시판에 새 글 작성할 때만 설정 가능
const isAdmin = computed(() => auth.user?.role === 'ADMIN')
const canNotice = computed(() => isAdmin.value && category === 'community' && !isEdit.value)
const title = ref('')
const content = ref('')
const notice = ref(false)
const tagGroups = ref([])
const selectedTagIds = ref([])
const loading = ref(false)
@@ -65,6 +71,7 @@ async function submit() {
title: title.value.trim(),
content: content.value,
category,
notice: canNotice.value ? notice.value : false,
tagIds: selectedTagIds.value,
}
try {
@@ -97,6 +104,12 @@ onMounted(async () => {
<form class="write-form" @submit.prevent="submit">
<input v-model="title" type="text" placeholder="제목" maxlength="200" :disabled="loading" />
<!-- 공지 등록 (관리자, 커뮤니티 ) -->
<label v-if="canNotice" class="notice-check">
<input v-model="notice" type="checkbox" :disabled="loading" />
📌 공지로 등록 (목록 최상단 고정)
</label>
<!-- 태그 선택 (DB 등록 태그를 뱃지로 토글) -->
<div class="tag-select">
<div v-if="!allTags.length" class="hint">
@@ -178,6 +191,17 @@ h1 {
font-size: 0.85rem;
opacity: 0.65;
}
.notice-check {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.9rem;
cursor: pointer;
}
.notice-check input {
width: auto;
cursor: pointer;
}
.buttons {
display: flex;
justify-content: flex-end;