同步设置
This commit is contained in:
1 parent
832261739f
commit
92aaf6fbb8
28 files changed
+705
-227
No files matched your search
@@ -4,21 +4,22 @@ import type {
|
||||
} from '~/types/image'
|
||||
import { isUnauthorizedError } from './useAuth'
|
||||
import { prepareFilesForUpload } from './useClipboardImage'
|
||||
import { normalizeUploadTagNames } from './useUploadPreferences'
|
||||
|
||||
const MAX_FILES = 10
|
||||
|
||||
export function useImageUpload() {
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
const { compressEnabled, clientWebpQuality, lastTagIds } = useUploadPreferences()
|
||||
const { items: tagItems } = useTags()
|
||||
const { compressEnabled, clientWebpQuality, uploadTagNames } = useUploadPreferences()
|
||||
const { load: loadUploadPolicy } = useUploadPolicy()
|
||||
const uploading = ref(false)
|
||||
const progressItems = ref<UploadProgressItem[]>([])
|
||||
const lastUploadResult = ref<UploadResponse | null>(null)
|
||||
|
||||
async function uploadFiles(
|
||||
files: File[],
|
||||
options?: { notify?: boolean, tagIds?: number[] }
|
||||
options?: { notify?: boolean }
|
||||
) {
|
||||
if (uploading.value) return
|
||||
|
||||
@@ -43,10 +44,27 @@ export function useImageUpload() {
|
||||
}))
|
||||
|
||||
try {
|
||||
const prepared = await prepareFilesForUpload(files, {
|
||||
const preparedFiles = await prepareFilesForUpload(files, {
|
||||
enabled: compressEnabled.value,
|
||||
quality: clientWebpQuality.value / 100
|
||||
})
|
||||
const currentPolicy = await loadUploadPolicy().catch(() => null)
|
||||
const maxFileSizeMb = currentPolicy?.imageMaxFileSizeMb ?? 10
|
||||
const prepared = preparedFiles.filter((file) => {
|
||||
if (file.size <= maxFileSizeMb * 1024 * 1024) return true
|
||||
toast.add({
|
||||
title: t('files.fileTooLarge', {
|
||||
name: file.name,
|
||||
limit: maxFileSizeMb
|
||||
}),
|
||||
color: 'error'
|
||||
})
|
||||
return false
|
||||
})
|
||||
if (!prepared.length) {
|
||||
progressItems.value = []
|
||||
return
|
||||
}
|
||||
|
||||
progressItems.value = prepared.map((file, index) => ({
|
||||
name: file.name,
|
||||
@@ -59,15 +77,9 @@ export function useImageUpload() {
|
||||
formData.append('files', file, file.name)
|
||||
}
|
||||
|
||||
const tagIds = options?.tagIds ?? lastTagIds.value
|
||||
if (tagIds.length) {
|
||||
const names = tagIds
|
||||
.map(id => tagItems.value.find(tag => tag.id === id)?.name)
|
||||
.filter((name): name is string => Boolean(name))
|
||||
if (names.length) {
|
||||
formData.append('tagNames', JSON.stringify(names))
|
||||
}
|
||||
lastTagIds.value = tagIds
|
||||
const tagNames = normalizeUploadTagNames(uploadTagNames.value).join(',')
|
||||
if (tagNames) {
|
||||
formData.append('tagNames', tagNames)
|
||||
}
|
||||
|
||||
const response = await $fetch<UploadResponse>('/api/images/upload', {
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { UploadProgressItem } from '~/types/image'
|
||||
import type { FileItem, FileListResponse, FileUploadResponse } from '~/types/file'
|
||||
import type { CopyFormat, UploadMediaKind } from './useUploadPreferences'
|
||||
import { isUnauthorizedError } from './useAuth'
|
||||
import { normalizeUploadTagNames } from './useUploadPreferences'
|
||||
|
||||
const MAX_FILES = 10
|
||||
|
||||
@@ -54,10 +55,9 @@ export function useMediaUpload(kind: UploadMediaKind) {
|
||||
autoCopyMarkdown,
|
||||
copyFormat,
|
||||
transcodeToHls,
|
||||
lastTagIds,
|
||||
uploadTagNames,
|
||||
loadPreferences
|
||||
} = useUploadPreferences(kind)
|
||||
const { items: tagItems, fetchTags } = useTags()
|
||||
|
||||
const uploading = ref(false)
|
||||
const progressItems = ref<UploadProgressItem[]>([])
|
||||
@@ -209,6 +209,19 @@ export function useMediaUpload(kind: UploadMediaKind) {
|
||||
})
|
||||
return false
|
||||
}
|
||||
const maxFileSizeMb = kind === 'video'
|
||||
? (currentPolicy?.videoMaxFileSizeMb ?? 500)
|
||||
: (currentPolicy?.fileMaxFileSizeMb ?? 100)
|
||||
if (file.size > maxFileSizeMb * 1024 * 1024) {
|
||||
toast.add({
|
||||
title: t('files.fileTooLarge', {
|
||||
name: file.name,
|
||||
limit: maxFileSizeMb
|
||||
}),
|
||||
color: 'error'
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if (!acceptedFiles.length) return
|
||||
@@ -234,14 +247,9 @@ export function useMediaUpload(kind: UploadMediaKind) {
|
||||
if (kind === 'video' && transcodeToHls.value) {
|
||||
formData.append('transcode', '1')
|
||||
}
|
||||
if (lastTagIds.value.length) {
|
||||
await fetchTags()
|
||||
const names = lastTagIds.value
|
||||
.map(id => tagItems.value.find(tag => tag.id === id)?.name)
|
||||
.filter((name): name is string => Boolean(name))
|
||||
if (names.length) {
|
||||
formData.append('tagNames', JSON.stringify(names))
|
||||
}
|
||||
const tagNames = normalizeUploadTagNames(uploadTagNames.value).join(',')
|
||||
if (tagNames) {
|
||||
formData.append('tagNames', tagNames)
|
||||
}
|
||||
|
||||
progressItems.value = progressItems.value.map(item => ({
|
||||
|
||||
@@ -2,6 +2,9 @@ interface UploadPolicy {
|
||||
allowedMimeTypes: string[]
|
||||
allowedVideoExtensions: string[]
|
||||
forbiddenFileExtensions: string[]
|
||||
imageMaxFileSizeMb: number
|
||||
videoMaxFileSizeMb: number
|
||||
fileMaxFileSizeMb: number
|
||||
}
|
||||
|
||||
const policy = ref<UploadPolicy | null>(null)
|
||||
@@ -21,7 +24,10 @@ export function useUploadPolicy() {
|
||||
policy.value = {
|
||||
allowedMimeTypes: [...data.allowedMimeTypes],
|
||||
allowedVideoExtensions: [...data.allowedVideoExtensions],
|
||||
forbiddenFileExtensions: [...data.forbiddenFileExtensions]
|
||||
forbiddenFileExtensions: [...data.forbiddenFileExtensions],
|
||||
imageMaxFileSizeMb: data.imageMaxFileSizeMb,
|
||||
videoMaxFileSizeMb: data.videoMaxFileSizeMb,
|
||||
fileMaxFileSizeMb: data.fileMaxFileSizeMb
|
||||
}
|
||||
return policy.value
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface UploadPreferences {
|
||||
autoCopyMarkdown: boolean
|
||||
copyFormat: CopyFormat
|
||||
clientWebpQuality: number
|
||||
lastTagIds: number[]
|
||||
uploadTagNames: string[]
|
||||
/** 视频床专属:上传后转码为 HLS(m3u8 + 分片) */
|
||||
transcodeToHls: boolean
|
||||
}
|
||||
@@ -23,10 +23,21 @@ const DEFAULTS: UploadPreferences = {
|
||||
autoCopyMarkdown: false,
|
||||
copyFormat: 'markdown',
|
||||
clientWebpQuality: 80,
|
||||
lastTagIds: [],
|
||||
uploadTagNames: [],
|
||||
transcodeToHls: false
|
||||
}
|
||||
|
||||
export function normalizeUploadTagNames(value: string | readonly string[]): string[] {
|
||||
const parts = typeof value === 'string'
|
||||
? value.split(/[,,\n]/)
|
||||
: value.flatMap(item => String(item).split(/[,,\n]/))
|
||||
return [...new Set(
|
||||
parts
|
||||
.map(name => name.trim())
|
||||
.filter(name => Boolean(name) && name.length <= 32)
|
||||
)]
|
||||
}
|
||||
|
||||
function clampQuality(value: unknown): number {
|
||||
const num = Number(value)
|
||||
if (!Number.isFinite(num)) return DEFAULTS.clientWebpQuality
|
||||
@@ -49,9 +60,8 @@ function readStored(kind: UploadMediaKind): UploadPreferences {
|
||||
autoCopyMarkdown: parsed.autoCopyMarkdown === true,
|
||||
copyFormat: isCopyFormat(parsed.copyFormat) ? parsed.copyFormat : DEFAULTS.copyFormat,
|
||||
clientWebpQuality: clampQuality(parsed.clientWebpQuality),
|
||||
lastTagIds: Array.isArray(parsed.lastTagIds)
|
||||
? parsed.lastTagIds.filter(id => Number.isInteger(id) && id > 0)
|
||||
: DEFAULTS.lastTagIds,
|
||||
/** 标签输入只在当前页面会话内生效,刷新后默认为空。 */
|
||||
uploadTagNames: [...DEFAULTS.uploadTagNames],
|
||||
transcodeToHls: parsed.transcodeToHls === true
|
||||
}
|
||||
} catch {
|
||||
@@ -69,17 +79,23 @@ export function useUploadPreferences(kind: UploadMediaKind = 'image') {
|
||||
const autoCopyMarkdown = useState(`upload-pref-auto-md-${kind}`, () => DEFAULTS.autoCopyMarkdown)
|
||||
const copyFormat = useState<CopyFormat>(`upload-pref-copy-format-${kind}`, () => DEFAULTS.copyFormat)
|
||||
const clientWebpQuality = useState(`upload-pref-webp-quality-${kind}`, () => DEFAULTS.clientWebpQuality)
|
||||
const lastTagIds = useState<number[]>(`upload-pref-last-tag-ids-${kind}`, () => DEFAULTS.lastTagIds)
|
||||
const uploadTagNames = useState<string[]>(
|
||||
`upload-pref-tag-names-${kind}`,
|
||||
() => [...DEFAULTS.uploadTagNames]
|
||||
)
|
||||
const transcodeToHls = useState(`upload-pref-transcode-${kind}`, () => DEFAULTS.transcodeToHls)
|
||||
const loaded = useState(`upload-pref-loaded-${kind}`, () => false)
|
||||
|
||||
function loadPreferences() {
|
||||
const firstLoad = !loaded.value
|
||||
const stored = readStored(kind)
|
||||
compressEnabled.value = stored.compressEnabled
|
||||
autoCopyMarkdown.value = stored.autoCopyMarkdown
|
||||
copyFormat.value = stored.copyFormat
|
||||
clientWebpQuality.value = stored.clientWebpQuality
|
||||
lastTagIds.value = stored.lastTagIds
|
||||
if (firstLoad) {
|
||||
uploadTagNames.value = [...stored.uploadTagNames]
|
||||
}
|
||||
transcodeToHls.value = stored.transcodeToHls
|
||||
loaded.value = true
|
||||
}
|
||||
@@ -94,7 +110,7 @@ export function useUploadPreferences(kind: UploadMediaKind = 'image') {
|
||||
autoCopyMarkdown: autoCopyMarkdown.value,
|
||||
copyFormat: copyFormat.value,
|
||||
clientWebpQuality: clampQuality(clientWebpQuality.value),
|
||||
lastTagIds: lastTagIds.value,
|
||||
uploadTagNames: [...DEFAULTS.uploadTagNames],
|
||||
transcodeToHls: transcodeToHls.value
|
||||
})
|
||||
}
|
||||
@@ -104,12 +120,13 @@ export function useUploadPreferences(kind: UploadMediaKind = 'image') {
|
||||
autoCopyMarkdown.value = DEFAULTS.autoCopyMarkdown
|
||||
copyFormat.value = DEFAULTS.copyFormat
|
||||
clientWebpQuality.value = DEFAULTS.clientWebpQuality
|
||||
uploadTagNames.value = [...DEFAULTS.uploadTagNames]
|
||||
transcodeToHls.value = DEFAULTS.transcodeToHls
|
||||
savePreferences()
|
||||
}
|
||||
|
||||
watch(
|
||||
[compressEnabled, autoCopyMarkdown, copyFormat, clientWebpQuality, lastTagIds, transcodeToHls],
|
||||
[compressEnabled, autoCopyMarkdown, copyFormat, clientWebpQuality, transcodeToHls],
|
||||
() => {
|
||||
if (loaded.value) {
|
||||
savePreferences()
|
||||
@@ -123,7 +140,7 @@ export function useUploadPreferences(kind: UploadMediaKind = 'image') {
|
||||
autoCopyMarkdown,
|
||||
copyFormat,
|
||||
clientWebpQuality,
|
||||
lastTagIds,
|
||||
uploadTagNames,
|
||||
transcodeToHls,
|
||||
loaded,
|
||||
loadPreferences,
|
||||
|
||||
Reference in new issue
Block a user