From b5ec579e5dba75e8ac2acfe7ac18a80200bbe2d1 Mon Sep 17 00:00:00 2001 From: zenn Date: Tue, 31 Mar 2026 15:00:07 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A6=B4=EB=A6=AC=EC=8A=A4:=20v1.2.58=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20compact=20=EC=B9=B4=EB=93=9C=20=EC=A0=84?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/update.md | 4 + frontend/src/views/AdminView.vue | 216 +++++++++++++++++++++---------- 2 files changed, 150 insertions(+), 70 deletions(-) diff --git a/docs/update.md b/docs/update.md index 805983d..642c224 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,9 @@ # 업데이트 로그 +## 2026-03-31 v1.2.58 +- 관리자 아이템 관리 카드를 썸네일과 제목만 보이는 compact 카드로 줄여, 대량 업로드된 이미지도 훨씬 높은 밀도로 탐색할 수 있게 정리함. +- 카드 클릭 시 상세 정보를 모달로 열고 이미지 다운로드, 기본 템플릿 추가, 삭제를 모달 안에서 결정하는 흐름으로 바꿈. + ## 2026-03-31 v1.2.57 - 관리자 오른쪽 사이드에서 Featured, Game Summary, Users 패널을 완전히 제거하고, 티어표 요청 모드에는 모드 전환 탭만 남기도록 정리함. diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue index 809e22d..e06bb02 100644 --- a/frontend/src/views/AdminView.vue +++ b/frontend/src/views/AdminView.vue @@ -48,9 +48,12 @@ const previewTierList = ref(null) const userPasswordModalOpen = ref(false) const userDeleteModalOpen = ref(false) const userRoleModalOpen = ref(false) +const customItemModalOpen = ref(false) +const customItemDeleteModalOpen = ref(false) const modalTargetUser = ref(null) const modalPasswordDraft = ref('') const modalRoleNextAdmin = ref(false) +const modalTargetCustomItem = ref(null) const users = ref([]) @@ -855,18 +858,42 @@ function moveCustomItemPage(direction) { refreshCustomItems() } -async function removeCustomItem(item) { +function openCustomItemModal(item) { + modalTargetCustomItem.value = item || null + customItemModalOpen.value = true +} + +function closeCustomItemModal() { + customItemModalOpen.value = false + modalTargetCustomItem.value = null +} + +function openCustomItemDeleteModal(item) { + if (!item) return + if (item.usageCount > 0) { + error.value = '사용 중인 커스텀 이미지는 먼저 참조를 정리해야 삭제할 수 있어요.' + return + } + modalTargetCustomItem.value = item + customItemDeleteModalOpen.value = true +} + +function closeCustomItemDeleteModal() { + customItemDeleteModalOpen.value = false +} + +async function removeCustomItem(item = modalTargetCustomItem.value) { resetMessages() + if (!item) return if (item.usageCount > 0) { error.value = '사용 중인 커스텀 이미지는 먼저 참조를 정리해야 삭제할 수 있어요.' return } - const ok = window.confirm(`"${item.label}" 미사용 커스텀 이미지를 삭제할까요?`) - if (!ok) return - try { await api.deleteAdminCustomItem(item.id) + closeCustomItemDeleteModal() + closeCustomItemModal() await refreshCustomItems() success.value = '미사용 커스텀 이미지를 삭제했어요.' } catch (e) { @@ -900,6 +927,7 @@ async function promoteCustomItem(item) { await api.promoteAdminCustomItem(item.id, { gameId: customItemTargetGameId.value }) const targetGameName = games.value.find((game) => game.id === customItemTargetGameId.value)?.name || customItemTargetGameId.value if (selectedGameId.value === customItemTargetGameId.value) await loadGame() + closeCustomItemModal() success.value = `"${item.label}" 아이템을 ${targetGameName} 기본 템플릿으로 추가했어요.` } catch (e) { error.value = '커스텀 아이템을 기본 템플릿으로 가져오지 못했어요.' @@ -1349,37 +1377,10 @@ async function saveFeaturedOrder() {
조건에 맞는 커스텀 아이템이 없어요.
-
+ - -
-
- +
{{ item.label }}
+
@@ -1671,6 +1672,51 @@ async function saveFeaturedOrder() {
+
+ +
+ +
+ +
+