릴리스: v1.3.25 관리자 게임 선택 UX와 세션 보안 보강
This commit is contained in:
@@ -22,6 +22,8 @@ const games = ref([])
|
||||
const selectedGameId = ref('')
|
||||
const selectedGame = ref(null)
|
||||
const featuredGameIds = ref([])
|
||||
const gameAdminQuery = ref('')
|
||||
const gameAdminSort = ref('recent')
|
||||
|
||||
const customItems = ref([])
|
||||
const customItemQuery = ref('')
|
||||
@@ -104,6 +106,19 @@ const featuredGames = computed(() =>
|
||||
.filter(Boolean)
|
||||
)
|
||||
const availableGamesForFeatured = computed(() => games.value.filter((game) => !featuredGameIds.value.includes(game.id)))
|
||||
const filteredAdminGames = computed(() => {
|
||||
const query = gameAdminQuery.value.trim().toLowerCase()
|
||||
const list = games.value.filter((game) => {
|
||||
if (!query) return true
|
||||
const haystack = `${game.name || ''} ${game.id || ''}`.toLowerCase()
|
||||
return haystack.includes(query)
|
||||
})
|
||||
|
||||
return list.slice().sort((a, b) => {
|
||||
if (gameAdminSort.value === 'oldest') return Number(a.createdAt || 0) - Number(b.createdAt || 0)
|
||||
return Number(b.createdAt || 0) - Number(a.createdAt || 0)
|
||||
})
|
||||
})
|
||||
const importModalItemCount = computed(() => importModalItems.value.length)
|
||||
const activeTabTitle = computed(() => {
|
||||
if (activeTab.value === 'featured') return '목록 관리'
|
||||
@@ -378,6 +393,12 @@ async function handleSelectedGameChange(event) {
|
||||
await loadGame()
|
||||
}
|
||||
|
||||
async function selectAdminGame(gameId) {
|
||||
if (!gameId || selectedGameId.value === gameId) return
|
||||
selectedGameId.value = gameId
|
||||
await loadGame()
|
||||
}
|
||||
|
||||
async function refreshGames() {
|
||||
try {
|
||||
const data = await api.listGames()
|
||||
@@ -2030,10 +2051,25 @@ async function saveFeaturedOrder() {
|
||||
<div class="adminSidebar__label">Game</div>
|
||||
<div class="adminSidebar__group">
|
||||
<button class="btn btn--primary" @click="openGameCreateModal">새 게임 생성</button>
|
||||
<select :value="selectedGameId" class="select" @change="handleSelectedGameChange">
|
||||
<option value="">게임을 선택해주세요</option>
|
||||
<option v-for="game in games" :key="game.id" :value="game.id">{{ game.name }} ({{ game.id }})</option>
|
||||
<input v-model="gameAdminQuery" class="input" placeholder="게임 이름 또는 ID 검색" />
|
||||
<select v-model="gameAdminSort" class="select">
|
||||
<option value="recent">최신순</option>
|
||||
<option value="oldest">오래된순</option>
|
||||
</select>
|
||||
<div class="adminGamePicker">
|
||||
<button
|
||||
v-for="game in filteredAdminGames"
|
||||
:key="game.id"
|
||||
class="adminGamePicker__item"
|
||||
:class="{ 'adminGamePicker__item--active': selectedGameId === game.id }"
|
||||
type="button"
|
||||
@click="selectAdminGame(game.id)"
|
||||
>
|
||||
<span class="adminGamePicker__name">{{ game.name }}</span>
|
||||
<span class="adminGamePicker__meta">{{ game.id }}</span>
|
||||
</button>
|
||||
<div v-if="!filteredAdminGames.length" class="hint hint--tight">검색 결과가 없어요.</div>
|
||||
</div>
|
||||
<div v-if="selectedGameId && !hasSelectedGame && !isGameLoading" class="hint hint--tight">선택된 게임 ID: {{ selectedGameId }}</div>
|
||||
</div>
|
||||
<div v-if="hasSelectedGame" class="adminSidebar__group">
|
||||
@@ -2370,6 +2406,39 @@ async function saveFeaturedOrder() {
|
||||
font-weight: 800;
|
||||
color: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
.adminGamePicker {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
max-height: 320px;
|
||||
overflow: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
.adminGamePicker__item {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
padding: 11px 12px;
|
||||
text-align: left;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
cursor: pointer;
|
||||
}
|
||||
.adminGamePicker__item--active {
|
||||
border-color: rgba(77, 127, 233, 0.58);
|
||||
background: rgba(77, 127, 233, 0.12);
|
||||
}
|
||||
.adminGamePicker__name {
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
.adminGamePicker__meta {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.56);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.sidebarStat {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
|
||||
Reference in New Issue
Block a user