릴리스: v0.1.48 템플릿 등록 요청 체크리스트 보강
This commit is contained in:
@@ -1088,7 +1088,7 @@ async function saveFeaturedOrder() {
|
||||
<div class="sectionHeader">
|
||||
<div>
|
||||
<div class="panel__title">사용자 템플릿 요청</div>
|
||||
<div class="hint hint--tight">freeform 템플릿 등록 요청과 기존 게임 템플릿 업데이트 요청을 여기서 승인하거나 반려할 수 있어요.</div>
|
||||
<div class="hint hint--tight">freeform 템플릿 등록 요청과 기존 게임 템플릿 업데이트 요청을 여기서 승인하거나 반려할 수 있어요. 반려한 요청은 대기 목록에서 바로 제외됩니다.</div>
|
||||
</div>
|
||||
<button class="btn btn--ghost" @click="refreshTemplateRequests">새로고침</button>
|
||||
</div>
|
||||
@@ -1125,7 +1125,7 @@ async function saveFeaturedOrder() {
|
||||
<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>
|
||||
<button class="btn btn--danger" :disabled="request.isHandling" @click="rejectTemplateRequest(request)">반려 후 숨김</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
@@ -37,6 +37,7 @@ const error = ref('')
|
||||
const isSaving = ref(false)
|
||||
const isExporting = ref(false)
|
||||
const isSaveModalOpen = ref(false)
|
||||
const isTemplateRequestModalOpen = ref(false)
|
||||
const ownerId = ref('')
|
||||
const authorName = ref('')
|
||||
const authorAccountName = ref('')
|
||||
@@ -97,6 +98,19 @@ const canRequestTemplateCreate = computed(
|
||||
const canRequestTemplateUpdate = computed(
|
||||
() => canEdit.value && !isNewTierList.value && gameId.value !== 'freeform' && customItems.value.length > 0
|
||||
)
|
||||
const templateRequestChecks = computed(() => [
|
||||
{
|
||||
id: 'title',
|
||||
label: '티어표 이름(게임 이름)을 직접 입력했는지',
|
||||
passed: !!(title.value || '').trim() && (title.value || '').trim() !== (gameName.value || '').trim(),
|
||||
},
|
||||
{
|
||||
id: 'empty-board',
|
||||
label: '등록한 이미지를 티어에 배치하지 않은 원본 상태인지',
|
||||
passed: !hasPlacedItems.value,
|
||||
},
|
||||
])
|
||||
const canSubmitTemplateCreateRequest = computed(() => templateRequestChecks.value.every((item) => item.passed))
|
||||
|
||||
watch(error, (message) => {
|
||||
if (!message) return
|
||||
@@ -455,6 +469,14 @@ function closeSaveModal() {
|
||||
isSaveModalOpen.value = false
|
||||
}
|
||||
|
||||
function openTemplateRequestModal() {
|
||||
isTemplateRequestModalOpen.value = true
|
||||
}
|
||||
|
||||
function closeTemplateRequestModal() {
|
||||
isTemplateRequestModalOpen.value = false
|
||||
}
|
||||
|
||||
async function removeTierList() {
|
||||
if (!canEdit.value || isNewTierList.value) return
|
||||
error.value = ''
|
||||
@@ -494,8 +516,13 @@ async function requestTemplate(type) {
|
||||
isRequestingTemplate.value = true
|
||||
await persistTierList({ showModal: false })
|
||||
await api.requestTierListTemplate(tierListId.value, { type })
|
||||
if (type === 'create') closeTemplateRequestModal()
|
||||
toast.success(type === 'create' ? '템플릿 등록 요청을 보냈어요.' : '템플릿 업데이트 요청을 보냈어요.')
|
||||
} catch (e) {
|
||||
if (e?.status === 400 && e?.data?.error === 'title_required') {
|
||||
toast.error('템플릿 등록 요청 전에는 티어표 이름을 직접 입력해주세요.')
|
||||
return
|
||||
}
|
||||
if (e?.status === 409) {
|
||||
toast.error('이미 처리 대기 중인 같은 요청이 있어요.')
|
||||
return
|
||||
@@ -504,6 +531,10 @@ async function requestTemplate(type) {
|
||||
toast.error('템플릿 등록 요청은 보드를 비운 상태에서만 보낼 수 있어요.')
|
||||
return
|
||||
}
|
||||
if (e?.status === 400 && e?.data?.error === 'custom_items_required') {
|
||||
toast.error('먼저 커스텀 아이템을 추가한 뒤 요청해주세요.')
|
||||
return
|
||||
}
|
||||
toast.error(type === 'create' ? '템플릿 등록 요청에 실패했어요.' : '템플릿 업데이트 요청에 실패했어요.')
|
||||
} finally {
|
||||
isRequestingTemplate.value = false
|
||||
@@ -629,9 +660,9 @@ onUnmounted(() => {
|
||||
v-if="canRequestTemplateCreate"
|
||||
class="btn btn--ghost"
|
||||
:disabled="isRequestingTemplate"
|
||||
@click="requestTemplate('create')"
|
||||
@click="openTemplateRequestModal"
|
||||
>
|
||||
{{ isRequestingTemplate ? '요청중...' : '템플릿 등록 요청' }}
|
||||
템플릿 등록 요청
|
||||
</button>
|
||||
<button
|
||||
v-if="canRequestTemplateUpdate"
|
||||
@@ -660,6 +691,35 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isTemplateRequestModalOpen" class="modalOverlay" @click.self="closeTemplateRequestModal">
|
||||
<div class="modalCard" role="dialog" aria-modal="true" aria-labelledby="templateRequestTitle">
|
||||
<div id="templateRequestTitle" class="modalCard__title">템플릿 등록 요청</div>
|
||||
<div class="modalCard__desc">
|
||||
여러 사용자가 비슷한 주제로 요청할 수 있으니, 관리자에게 전달되기 전에 아래 조건을 먼저 확인해주세요.
|
||||
</div>
|
||||
<div class="requestChecklist">
|
||||
<div
|
||||
v-for="check in templateRequestChecks"
|
||||
:key="check.id"
|
||||
class="requestChecklist__item"
|
||||
:class="{ 'requestChecklist__item--passed': check.passed }"
|
||||
>
|
||||
<span class="requestChecklist__icon">{{ check.passed ? '완료' : '확인 필요' }}</span>
|
||||
<span>{{ check.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="requestChecklist__hint">
|
||||
제목이 명확하고, 보드는 비워둔 채 원본 아이템만 정리되어 있을수록 관리자가 새 게임 템플릿으로 빠르게 등록하기 쉬워져요.
|
||||
</div>
|
||||
<div class="modalCard__actions">
|
||||
<button class="btn btn--ghost" @click="closeTemplateRequestModal">취소</button>
|
||||
<button class="btn btn--save" :disabled="!canSubmitTemplateCreateRequest || isRequestingTemplate" @click="requestTemplate('create')">
|
||||
{{ isRequestingTemplate ? '요청중...' : '등록 요청 보내기' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="layout" :style="{ '--thumb-size': `${iconSize}px` }">
|
||||
<div ref="boardEl" class="board">
|
||||
<div v-if="canEdit && !isExporting" class="boardTools">
|
||||
@@ -1018,6 +1078,36 @@ onUnmounted(() => {
|
||||
justify-content: flex-end;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.requestChecklist {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
.requestChecklist__item {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(251, 191, 36, 0.22);
|
||||
background: rgba(251, 191, 36, 0.08);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.requestChecklist__item--passed {
|
||||
border-color: rgba(52, 211, 153, 0.24);
|
||||
background: rgba(52, 211, 153, 0.1);
|
||||
}
|
||||
.requestChecklist__icon {
|
||||
flex: 0 0 auto;
|
||||
min-width: 56px;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.requestChecklist__hint {
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
opacity: 0.78;
|
||||
}
|
||||
.boardTools {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
Reference in New Issue
Block a user