게시물 Export 용량 기준 분할 추가 v1.5.25

This commit is contained in:
2026-06-01 16:20:35 +09:00
parent 5735fd5046
commit 212bd3f34f
14 changed files with 316 additions and 41 deletions

View File

@@ -29,6 +29,8 @@ const postExportYear = ref(new Date().getFullYear())
const postExportMonth = ref(new Date().getMonth() + 1)
const postExportDateFrom = ref('')
const postExportDateTo = ref('')
const postExportChunkSize = ref(500)
const postExportMaxFileSizeMb = ref(500)
const errorMessage = ref('')
const toast = ref(null)
const logoInputRef = ref(null)
@@ -212,6 +214,15 @@ const canRequestPostExport = computed(() => {
return false
}
const hasValidSplitOptions = postExportChunkSize.value >= 1
&& postExportChunkSize.value <= 500
&& postExportMaxFileSizeMb.value >= 10
&& postExportMaxFileSizeMb.value <= 2048
if (!hasValidSplitOptions) {
return false
}
if (postExportDateRangeMode.value === 'custom') {
return Boolean(
postExportDateFrom.value
@@ -236,6 +247,10 @@ const postExportRequestTitle = computed(() => {
return '올바른 시작일과 종료일을 선택해 주세요.'
}
if (!canRequestPostExport.value) {
return 'ZIP당 최대 게시물 수와 목표 용량을 확인해 주세요.'
}
return '게시물 Export 작업을 요청합니다.'
})
@@ -245,7 +260,8 @@ const postExportRequestTitle = computed(() => {
*/
const createPostExportRequestBody = () => {
const base = {
chunkSize: 100,
chunkSize: Number(postExportChunkSize.value),
maxFileSizeBytes: Number(postExportMaxFileSizeMb.value) * 1024 * 1024,
retentionDays: 100,
dateRangeMode: postExportDateRangeMode.value
}
@@ -2023,7 +2039,7 @@ onBeforeUnmount(() => {
Obsidian 호환 백업 준비
</p>
<p class="mt-1 text-sm leading-relaxed text-[#657080]">
전체·연도··직접 범위로 게시물을 골라 100 단위 ZIP 백업을 만듭니다.
전체·연도··직접 범위로 게시물을 골라 목표 용량 기준 ZIP 백업을 만듭니다.
</p>
</div>
<div class="grid gap-3">
@@ -2099,6 +2115,30 @@ onBeforeUnmount(() => {
>
</label>
</div>
<div class="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
v-model.number="postExportMaxFileSizeMb"
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"
>
</label>
<label class="grid gap-1 text-xs font-semibold text-[#5d6673]">
ZIP당 최대 게시물
<input
v-model.number="postExportChunkSize"
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"
>
</label>
</div>
<div class="flex items-center justify-end">
<button
class="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]"
@@ -2160,6 +2200,9 @@ onBeforeUnmount(() => {
<p class="mt-2 text-xs text-[#657080]">
요청: {{ formatPostDateTime(job.createdAt) }} · 만료: {{ formatPostDateTime(job.expiresAt) }}
</p>
<p class="mt-1 text-xs text-[#9aa3ad]">
목표 용량 {{ formatExportFileSize(job.maxFileSizeBytes) }} · 최대 {{ job.chunkSize }}/ZIP
</p>
</div>
<div class="flex shrink-0 items-center gap-2">
<button
@@ -2211,6 +2254,16 @@ onBeforeUnmount(() => {
</div>
</div>
<details
v-if="job.status === 'failed' && job.errorDetail"
class="admin-settings-screen__export-error mt-4 rounded-lg border border-[#ffd5d5] bg-[#fff7f7] p-3 text-xs text-[#8f2d2d]"
>
<summary class="cursor-pointer font-semibold">
실패 원인 보기
</summary>
<pre class="mt-2 max-h-40 overflow-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-relaxed">{{ job.errorDetail }}</pre>
</details>
<div v-if="job.files.length > 0" class="admin-settings-screen__export-files mt-4 overflow-hidden rounded-md border border-[#edf0f3]">
<div
v-for="file in job.files"