Files
FileHost/app/composables/useImageUpload.ts
T
O96u 469d3be735
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
release: v1.2.0 — unified images/ storage and legacy migration
Consolidate local images under data/images/, add docker migrate CLI,
startup index sync with orphan cleanup, and remove upload folder UI/API.
2026-08-28 17:18:03 +08:00

118 lines
2.9 KiB
TypeScript

import type {
UploadProgressItem,
UploadResponse
} from '~/types/image'
import { isUnauthorizedError } from './useAuth'
import { prepareFilesForUpload } from './useClipboardImage'
const MAX_FILES = 10
export function useImageUpload() {
const toast = useToast()
const { t } = useI18n()
const { compressEnabled, clientWebpQuality } = useUploadPreferences()
const uploading = ref(false)
const progressItems = ref<UploadProgressItem[]>([])
const lastUploadResult = ref<UploadResponse | null>(null)
async function uploadFiles(
files: File[],
options?: { notify?: boolean }
) {
if (uploading.value) return
if (!files.length) {
toast.add({ title: t('upload.selectImages'), color: 'warning' })
return
}
if (files.length > MAX_FILES) {
toast.add({
title: t('upload.maxFiles', { n: MAX_FILES }),
color: 'warning'
})
return
}
uploading.value = true
progressItems.value = files.map(file => ({
name: file.name,
status: 'pending',
progress: 0
}))
try {
const prepared = await prepareFilesForUpload(files, {
enabled: compressEnabled.value,
quality: clientWebpQuality.value / 100
})
progressItems.value = prepared.map((file, index) => ({
name: file.name,
status: 'uploading',
progress: Math.round(((index + 1) / prepared.length) * 50)
}))
const formData = new FormData()
for (const file of prepared) {
formData.append('files', file, file.name)
}
const response = await $fetch<UploadResponse>('/api/images/upload', {
method: 'POST',
body: formData
})
lastUploadResult.value = response
progressItems.value = prepared.map((file) => {
const failed = response.errors.find(error => error.name === file.name)
return {
name: file.name,
status: failed ? 'error' : 'success',
progress: 100,
error: failed?.error.message
}
})
if (response.items.length && options?.notify !== false) {
toast.add({
title: t('upload.uploadSuccess', { n: response.items.length }),
color: 'success'
})
}
if (response.errors.length) {
toast.add({
title: t('upload.uploadPartialFail', { n: response.errors.length }),
color: 'warning'
})
}
return response
} catch (error: unknown) {
if (isUnauthorizedError(error)) {
throw error
}
const message = error instanceof Error ? error.message : t('upload.uploadFailed')
progressItems.value = progressItems.value.map(item => ({
...item,
status: 'error',
progress: 100,
error: message
}))
toast.add({ title: message, color: 'error' })
throw error
} finally {
uploading.value = false
}
}
return {
uploading,
progressItems,
lastUploadResult,
uploadFiles
}
}