|
|
|
|
@@ -654,11 +654,7 @@ async function refreshTemplateRequests() {
|
|
|
|
|
...request,
|
|
|
|
|
draftGameId:
|
|
|
|
|
request.type === 'create'
|
|
|
|
|
? (request.sourceTierListTitle || '')
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
|
|
|
.replace(/^-+|-+$/g, '')
|
|
|
|
|
.slice(0, 80) || 'new-template'
|
|
|
|
|
? ('tmpl-' + String(request.id || 'request').replace(/[^a-zA-Z0-9]+/g, '').slice(0, 12).toLowerCase())
|
|
|
|
|
: request.targetGameId || request.sourceGameId || '',
|
|
|
|
|
draftGameName:
|
|
|
|
|
request.type === 'create'
|
|
|
|
|
@@ -1768,45 +1764,64 @@ async function saveFeaturedOrder() {
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="!templateRequests.length" class="hint">현재 처리 대기 중인 템플릿 요청이 없어요.</div>
|
|
|
|
|
<div v-else class="templateRequestList">
|
|
|
|
|
<article v-for="request in templateRequests" :key="request.id" class="templateRequestCard">
|
|
|
|
|
<div class="templateRequestCard__head">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="templateRequestCard__title">{{ request.sourceTierListTitle }}</div>
|
|
|
|
|
<div v-if="request.sourceDescription" class="templateRequestCard__desc">{{ request.sourceDescription }}</div>
|
|
|
|
|
<div class="templateRequestCard__meta">
|
|
|
|
|
{{ templateRequestTypeLabel(request) }} · {{ request.requesterName }} · {{ fmt(request.createdAt) }}
|
|
|
|
|
<div v-else class="templateRequestList">
|
|
|
|
|
<article v-for="request in templateRequests" :key="request.id" class="tierAdminCard templateRequestCard templateRequestCard--aligned">
|
|
|
|
|
<div class="templateRequestCard__side">
|
|
|
|
|
<button class="tierAdminCard__preview templateRequestCard__preview" type="button" @click="openTemplateRequestPreview(request)">
|
|
|
|
|
<img v-if="request.thumbnailSrc" class="tierAdminCard__thumb" :src="toApiUrl(request.thumbnailSrc)" :alt="request.sourceTierListTitle" />
|
|
|
|
|
<div v-else class="tierAdminCard__thumb tierAdminCard__thumb--empty"></div>
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<div class="templateRequestCard__thumbMeta">
|
|
|
|
|
<template v-if="request.type === 'create'">
|
|
|
|
|
<label class="templateRequestField">
|
|
|
|
|
<span class="templateRequestField__label">게임 이름</span>
|
|
|
|
|
<input v-model="request.draftGameName" class="input" placeholder="새 게임 이름" />
|
|
|
|
|
</label>
|
|
|
|
|
<label class="templateRequestField">
|
|
|
|
|
<span class="templateRequestField__label">게임 ID</span>
|
|
|
|
|
<input v-model="request.draftGameId" class="input" placeholder="임시 게임 ID" />
|
|
|
|
|
</label>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
|
|
|
|
<div class="templateRequestCard__thumbLabel">게임 이름</div>
|
|
|
|
|
<div class="templateRequestCard__thumbValue">{{ request.draftGameName || request.sourceGameName || '-' }}</div>
|
|
|
|
|
<div class="templateRequestCard__thumbLabel">게임 ID</div>
|
|
|
|
|
<div class="templateRequestCard__thumbValue">{{ request.draftGameId || request.sourceGameId || '-' }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="tierAdminCard__body">
|
|
|
|
|
<div class="tierAdminCard__head">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="tierAdminCard__title">{{ request.sourceTierListTitle }}</div>
|
|
|
|
|
<div v-if="request.sourceDescription" class="tierAdminCard__desc">{{ request.sourceDescription }}</div>
|
|
|
|
|
<div class="tierAdminCard__meta">
|
|
|
|
|
{{ templateRequestTypeLabel(request) }} · {{ request.requesterName }} · {{ fmt(request.createdAt) }}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tierAdminCard__meta">{{ templateRequestTargetLabel(request) }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="templateRequestCard__meta">{{ templateRequestTargetLabel(request) }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn--ghost btn--small" @click="openTemplateRequestPreview(request)">
|
|
|
|
|
요청 미리보기
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="request.items?.length" class="templateRequestItems">
|
|
|
|
|
<div v-for="item in request.items" :key="item.id" class="templateRequestItem">
|
|
|
|
|
<img class="templateRequestItem__thumb" :src="toApiUrl(item.src)" :alt="item.label" />
|
|
|
|
|
<div class="templateRequestItem__label">{{ item.label }}</div>
|
|
|
|
|
<div class="tierAdminCard__stats">
|
|
|
|
|
<span class="pill">추가 아이템 {{ request.items?.length || 0 }}개</span>
|
|
|
|
|
<span class="pill">{{ request.type === 'create' ? '새 템플릿' : '기존 템플릿 업데이트' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="request.type === 'create'" class="templateRequestCard__form">
|
|
|
|
|
<label class="templateRequestField">
|
|
|
|
|
<span class="templateRequestField__label">게임 이름</span>
|
|
|
|
|
<input v-model="request.draftGameName" class="input" placeholder="새 게임 이름" />
|
|
|
|
|
</label>
|
|
|
|
|
<label class="templateRequestField">
|
|
|
|
|
<span class="templateRequestField__label">게임 ID</span>
|
|
|
|
|
<input v-model="request.draftGameId" class="input" placeholder="새 게임 ID" />
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="request.items?.length" class="tierAdminItemList templateRequestCard__items">
|
|
|
|
|
<button v-for="item in request.items" :key="item.id" class="tierAdminItem" type="button">
|
|
|
|
|
<img class="tierAdminItem__thumb" :src="toApiUrl(item.src)" :alt="item.label" />
|
|
|
|
|
<div class="tierAdminItem__title">{{ item.label }}</div>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="templateRequestCard__actions">
|
|
|
|
|
<button class="btn btn--primary" :disabled="request.isHandling" @click="approveTemplateRequest(request)">
|
|
|
|
|
{{ request.isHandling ? '처리중...' : '승인' }}
|
|
|
|
|
</button>
|
|
|
|
|
<button class="btn btn--danger" :disabled="request.isHandling" @click="rejectTemplateRequest(request)">반려 후 숨김</button>
|
|
|
|
|
<div class="templateRequestCard__actions">
|
|
|
|
|
<button class="btn btn--primary" :disabled="request.isHandling" @click="approveTemplateRequest(request)">
|
|
|
|
|
{{ request.isHandling ? '처리중...' : '승인' }}
|
|
|
|
|
</button>
|
|
|
|
|
<button class="btn btn--danger" :disabled="request.isHandling" @click="rejectTemplateRequest(request)">반려 후 숨김</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
@@ -3826,72 +3841,35 @@ async function saveFeaturedOrder() {
|
|
|
|
|
gap: 14px;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 14px;
|
|
|
|
|
padding: 18px;
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
|
|
|
background: var(--theme-pill-bg);
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__head {
|
|
|
|
|
display: flex;
|
|
|
|
|
.templateRequestCard--aligned {
|
|
|
|
|
align-items: start;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__side {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
align-self: start;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__title {
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
.templateRequestCard__preview {
|
|
|
|
|
align-self: start;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__desc {
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
color: var(--theme-text-muted);
|
|
|
|
|
line-height: 1.55;
|
|
|
|
|
white-space: pre-line;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__meta {
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
opacity: 0.72;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestItems {
|
|
|
|
|
.templateRequestCard__thumbMeta {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestItem {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestItem__thumb {
|
|
|
|
|
width: 100%;
|
|
|
|
|
aspect-ratio: 1 / 1;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
|
|
|
background: var(--theme-surface-soft);
|
|
|
|
|
}
|
|
|
|
|
.templateRequestItem__label {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__form {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestField {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 6px;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestField__label {
|
|
|
|
|
.templateRequestCard__thumbLabel {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
color: var(--theme-text-faint);
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__thumbValue {
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
color: var(--theme-text);
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__items {
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
|
|
|
|
}
|
|
|
|
|
.templateRequestCard__actions {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|