diff --git a/src/components/dialog/ReorganizeDialog.vue b/src/components/dialog/ReorganizeDialog.vue index 38e4949e..0904cce7 100644 --- a/src/components/dialog/ReorganizeDialog.vue +++ b/src/components/dialog/ReorganizeDialog.vue @@ -89,6 +89,30 @@ const previewLoaded = ref(false) // 预览数据 const previewData = ref() +interface EpisodeFormatRecommendData { + rule_name?: string + rule_index?: number + pattern?: string + episode_format?: string + sample_file?: string + min_file_size_mb?: number + message?: string +} + +const episodeFormatRecommendState = reactive<{ + loading: boolean + ruleName?: string + sampleFile?: string + lastMessage?: string +}>({ + loading: false, + ruleName: undefined, + sampleFile: undefined, + lastMessage: undefined, +}) + +const episodeFormatRuleConfigured = ref(undefined) + function getFileItemKey(item?: FileItem) { return [item?.storage ?? '', item?.type ?? '', item?.path ?? ''].join('|') } @@ -414,6 +438,40 @@ const previewToggleIcon = computed(() => { return previewVisible.value ? 'mdi-eye-off-outline' : 'mdi-eye-outline' }) +const episodeFormatRecommendSourceItem = computed(() => { + if (transferForm.fileitem?.path) return transferForm.fileitem + if (normalizedItems.value.length !== 1) return undefined + return normalizedItems.value[0] +}) + +const canRecommendEpisodeFormat = computed(() => { + return ( + Boolean(episodeFormatRecommendSourceItem.value?.path) && + !progressDialog.value && + !episodeFormatRecommendState.loading + ) +}) + +const episodeFormatRecommendTooltip = computed(() => { + if (episodeFormatRecommendState.loading) return t('dialog.reorganize.episodeFormatRecommendLoading') + if (!episodeFormatRecommendSourceItem.value?.path) return t('dialog.reorganize.episodeFormatRecommendSelectFile') + if (episodeFormatRuleConfigured.value === false) return t('dialog.reorganize.episodeFormatRecommendNeedWords') + return t('dialog.reorganize.episodeFormatRecommendAction') +}) + +watch( + () => getFileItemKey(episodeFormatRecommendSourceItem.value), + sourceKey => { + transferForm.fileitem = episodeFormatRecommendSourceItem.value ?? ({} as FileItem) + if (!sourceKey) { + episodeFormatRecommendState.ruleName = undefined + episodeFormatRecommendState.sampleFile = undefined + episodeFormatRecommendState.lastMessage = undefined + } + }, + { immediate: true }, +) + // 构造整理请求 function createTransferPayload(options: { item?: FileItem; logid?: number; preview?: boolean }) { const payload: ManualTransferPayload = { @@ -434,6 +492,65 @@ async function requestManualTransfer( return await api.post(`transfer/manual?background=${background}`, payload) } +async function loadEpisodeFormatRuleConfiguration() { + try { + const result: { [key: string]: any } = await api.get('system/setting/EpisodeFormatRuleTable') + episodeFormatRuleConfigured.value = Boolean(result.data?.value?.length) + } catch (error) { + console.log(error) + episodeFormatRuleConfigured.value = undefined + } +} + +async function handleRecommendEpisodeFormat() { + const sourceItem = episodeFormatRecommendSourceItem.value + if (!sourceItem?.path) { + $toast.warning(t('dialog.reorganize.episodeFormatRecommendSelectFile')) + return + } + + if (episodeFormatRuleConfigured.value === false) { + $toast.warning(t('dialog.reorganize.episodeFormatRecommendNeedWords')) + return + } + + episodeFormatRecommendState.loading = true + + try { + const hasExistingEpisodeFormat = Boolean(transferForm.episode_format?.trim()) + const result = await api.post('transfer/episode-format/recommend', { + fileitem: sourceItem, + }) + + if (!result.success) { + $toast.error(result.message || t('dialog.reorganize.episodeFormatRecommendFailed')) + return + } + + const data = (result.data ?? {}) as EpisodeFormatRecommendData + if (!data.episode_format) { + $toast.error(t('dialog.reorganize.episodeFormatRecommendFailed')) + return + } + + transferForm.episode_format = data.episode_format + episodeFormatRecommendState.ruleName = data.rule_name + episodeFormatRecommendState.sampleFile = data.sample_file + episodeFormatRecommendState.lastMessage = data.message + + $toast.success( + hasExistingEpisodeFormat + ? t('dialog.reorganize.episodeFormatRecommendOverwriteSuccess') + : t('dialog.reorganize.episodeFormatRecommendSuccess'), + ) + } catch (error: any) { + console.log(error) + $toast.error(error?.message || t('dialog.reorganize.episodeFormatRecommendFailed')) + } finally { + episodeFormatRecommendState.loading = false + } +} + // 默认预览数据 function getDefaultPreviewData(): ManualTransferPreviewData { return { @@ -769,6 +886,7 @@ async function transfer(background: boolean = false) { onMounted(() => { loadDirectories() loadStorages() + loadEpisodeFormatRuleConfiguration() }) onUnmounted(() => { @@ -778,8 +896,15 @@ onUnmounted(() => { + +