게시물 내보내기 요청 카드 분리
This commit is contained in:
261
components/admin/AdminPostExportRequestCard.vue
Normal file
261
components/admin/AdminPostExportRequestCard.vue
Normal file
@@ -0,0 +1,261 @@
|
||||
<script setup>
|
||||
/**
|
||||
* 게시물 내보내기 요청 카드
|
||||
* @property {boolean} expanded - 펼침 여부
|
||||
* @property {string} dateRangeMode - 내보내기 범위 모드
|
||||
* @property {number} year - 내보내기 연도
|
||||
* @property {number} month - 내보내기 월
|
||||
* @property {string} dateFrom - 직접 범위 시작일
|
||||
* @property {string} dateTo - 직접 범위 종료일
|
||||
* @property {number} maxFileSizeMb - 목표 ZIP 용량
|
||||
* @property {number} chunkSize - ZIP당 최대 게시물 수
|
||||
* @property {Array} dateRangeModeOptions - 범위 옵션
|
||||
* @property {Array} yearOptions - 연도 옵션
|
||||
* @property {Array} monthOptions - 월 옵션
|
||||
* @property {boolean} canRequest - 요청 가능 여부
|
||||
* @property {boolean} requesting - 요청 중 여부
|
||||
* @property {boolean} hasActiveJobs - 진행 중 작업 여부
|
||||
* @property {string} requestTitle - 요청 버튼 안내 문구
|
||||
*/
|
||||
defineProps({
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dateRangeMode: {
|
||||
type: String,
|
||||
default: 'all'
|
||||
},
|
||||
year: {
|
||||
type: [Number, String],
|
||||
default: () => new Date().getFullYear()
|
||||
},
|
||||
month: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
dateFrom: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
dateTo: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
maxFileSizeMb: {
|
||||
type: [Number, String],
|
||||
default: 500
|
||||
},
|
||||
chunkSize: {
|
||||
type: [Number, String],
|
||||
default: 500
|
||||
},
|
||||
dateRangeModeOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
yearOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
monthOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
canRequest: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
requesting: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hasActiveJobs: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
requestTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
'toggle',
|
||||
'request',
|
||||
'update:dateRangeMode',
|
||||
'update:year',
|
||||
'update:month',
|
||||
'update:dateFrom',
|
||||
'update:dateTo',
|
||||
'update:maxFileSizeMb',
|
||||
'update:chunkSize'
|
||||
])
|
||||
|
||||
/**
|
||||
* 입력 이벤트 값을 문자열로 전달한다.
|
||||
* @param {Event} event - 입력 이벤트
|
||||
* @param {string} eventName - 전달할 이벤트 이름
|
||||
* @returns {void}
|
||||
*/
|
||||
const emitTextInputValue = (event, eventName) => {
|
||||
emit(eventName, event.target?.value || '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 숫자 입력 이벤트 값을 전달한다.
|
||||
* @param {Event} event - 입력 이벤트
|
||||
* @param {string} eventName - 전달할 이벤트 이름
|
||||
* @returns {void}
|
||||
*/
|
||||
const emitNumberInputValue = (event, eventName) => {
|
||||
const value = event.target?.value ?? ''
|
||||
emit(eventName, value === '' ? '' : Number(value))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="admin-settings-section-export"
|
||||
class="admin-post-export-request-card admin-settings-screen__card rounded-xl border border-[#e6e8eb] bg-white p-6 shadow-[0_1px_2px_rgba(15,23,42,0.04)]"
|
||||
>
|
||||
<div class="admin-settings-screen__card-head flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
|
||||
<div class="min-w-0">
|
||||
<h2 class="text-lg font-semibold text-[#15171a]">
|
||||
게시물 내보내기
|
||||
</h2>
|
||||
<p class="mt-1 text-sm leading-relaxed text-[#657080]">
|
||||
게시물을 Obsidian 호환 ZIP 백업으로 만들고, 준비된 분할 파일을 내려받습니다.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="inline-flex h-10 shrink-0 cursor-pointer items-center justify-center rounded-md bg-[#15171a] px-4 text-sm font-semibold text-white transition hover:bg-black"
|
||||
type="button"
|
||||
:aria-expanded="expanded"
|
||||
aria-controls="admin-settings-export-panel"
|
||||
@click="emit('toggle')"
|
||||
>
|
||||
{{ expanded ? '접기' : '내보내기' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="expanded"
|
||||
id="admin-settings-export-panel"
|
||||
class="admin-post-export-request-card__actions admin-settings-screen__export-actions mt-4 grid gap-4 rounded-lg border border-[#e6e8eb] bg-[#fbfcfd] p-4"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-semibold text-[#15171a]">
|
||||
Obsidian 호환 백업 준비
|
||||
</p>
|
||||
<p class="mt-1 text-sm leading-relaxed text-[#657080]">
|
||||
전체·연도·월·직접 범위로 게시물을 골라 목표 용량 기준 ZIP 백업을 만듭니다.
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid gap-3">
|
||||
<div class="admin-post-export-request-card__range admin-settings-screen__export-range grid gap-2 md:grid-cols-4">
|
||||
<div class="grid gap-1 text-xs font-semibold text-[#5d6673]">
|
||||
<span>범위</span>
|
||||
<AdminSelectInput
|
||||
:model-value="dateRangeMode"
|
||||
:options="dateRangeModeOptions"
|
||||
label="내보내기 범위"
|
||||
select-class="admin-settings-screen__export-select h-10 rounded-md border-[#dce0e5] text-sm font-semibold text-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
width-class="w-full"
|
||||
@update:model-value="emit('update:dateRangeMode', $event)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="dateRangeMode === 'year' || dateRangeMode === 'month'"
|
||||
class="grid gap-1 text-xs font-semibold text-[#5d6673]"
|
||||
>
|
||||
<span>연도</span>
|
||||
<AdminSelectInput
|
||||
:model-value="year"
|
||||
:options="yearOptions"
|
||||
label="내보내기 연도"
|
||||
select-class="admin-settings-screen__export-select h-10 rounded-md border-[#dce0e5] text-sm font-semibold text-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
width-class="w-full"
|
||||
@update:model-value="emit('update:year', $event)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="dateRangeMode === 'month'"
|
||||
class="grid gap-1 text-xs font-semibold text-[#5d6673]"
|
||||
>
|
||||
<span>월</span>
|
||||
<AdminSelectInput
|
||||
:model-value="month"
|
||||
:options="monthOptions"
|
||||
label="내보내기 월"
|
||||
select-class="admin-settings-screen__export-select h-10 rounded-md border-[#dce0e5] text-sm font-semibold text-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
width-class="w-full"
|
||||
@update:model-value="emit('update:month', $event)"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
v-if="dateRangeMode === 'custom'"
|
||||
class="grid gap-1 text-xs font-semibold text-[#5d6673]"
|
||||
>
|
||||
시작일
|
||||
<input
|
||||
:value="dateFrom"
|
||||
class="h-10 rounded-md border border-[#dce0e5] bg-white px-3 text-sm font-semibold text-[#15171a] outline-none focus:border-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
type="date"
|
||||
@input="emitTextInputValue($event, 'update:dateFrom')"
|
||||
>
|
||||
</label>
|
||||
<label
|
||||
v-if="dateRangeMode === 'custom'"
|
||||
class="grid gap-1 text-xs font-semibold text-[#5d6673]"
|
||||
>
|
||||
종료일
|
||||
<input
|
||||
:value="dateTo"
|
||||
class="h-10 rounded-md border border-[#dce0e5] bg-white px-3 text-sm font-semibold text-[#15171a] outline-none focus:border-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
type="date"
|
||||
@input="emitTextInputValue($event, 'update:dateTo')"
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
<div class="admin-post-export-request-card__split admin-settings-screen__export-split grid gap-2 md:grid-cols-2">
|
||||
<label class="grid gap-1 text-xs font-semibold text-[#5d6673]">
|
||||
목표 ZIP 용량 (MB)
|
||||
<input
|
||||
:value="maxFileSizeMb"
|
||||
class="h-10 rounded-md border border-[#dce0e5] bg-white px-3 text-sm font-semibold text-[#15171a] outline-none focus:border-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
type="number"
|
||||
min="10"
|
||||
max="2048"
|
||||
step="10"
|
||||
@input="emitNumberInputValue($event, 'update:maxFileSizeMb')"
|
||||
>
|
||||
</label>
|
||||
<label class="grid gap-1 text-xs font-semibold text-[#5d6673]">
|
||||
ZIP당 최대 게시물 수
|
||||
<input
|
||||
:value="chunkSize"
|
||||
class="h-10 rounded-md border border-[#dce0e5] bg-white px-3 text-sm font-semibold text-[#15171a] outline-none focus:border-[#15171a] focus:ring-1 focus:ring-[#15171a]"
|
||||
type="number"
|
||||
min="1"
|
||||
max="500"
|
||||
step="1"
|
||||
@input="emitNumberInputValue($event, 'update:chunkSize')"
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center justify-end">
|
||||
<button
|
||||
class="admin-post-export-request-card__request admin-settings-screen__export-request inline-flex h-10 shrink-0 cursor-pointer items-center justify-center rounded-md bg-[#15171a] px-4 text-sm font-semibold text-white transition hover:bg-black disabled:cursor-not-allowed disabled:bg-[#c7cdd4]"
|
||||
type="button"
|
||||
:disabled="!canRequest"
|
||||
:title="requestTitle"
|
||||
@click="emit('request')"
|
||||
>
|
||||
{{ requesting ? '요청 중...' : hasActiveJobs ? '내보내기 진행 중' : '내보내기 요청' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
Reference in New Issue
Block a user