优化识别词应用详情显示 (#481)

This commit is contained in:
Album
2026-05-31 17:51:05 +08:00
committed by GitHub
parent 258e64bca7
commit 261aaf17ad
4 changed files with 130 additions and 22 deletions

View File

@@ -103,11 +103,15 @@ interface EpisodeFormatRecommendData {
const episodeFormatRecommendState = reactive<{
loading: boolean
ruleName?: string
rulePattern?: string
generatedFormat?: string
sampleFile?: string
lastMessage?: string
}>({
loading: false,
ruleName: undefined,
rulePattern: undefined,
generatedFormat: undefined,
sampleFile: undefined,
lastMessage: undefined,
})
@@ -627,18 +631,99 @@ const previewFileRows = computed(() => {
// 标准化预览项中的识别词命中详情
function getPreviewApplyWords(item: ManualTransferPreviewItem) {
return (item.apply_words ?? []).filter(Boolean)
return [
...new Set(
(item.apply_words ?? [])
.map(word => word?.trim())
.filter((word): word is string => Boolean(word)),
),
]
}
// 手动整理识别词应用详情
const previewCustomWordDetails = computed(() => {
return filteredPreviewItems.value
.map(item => ({
sourceName: getFileName(item.source),
orgString: item.org_string,
applyWords: getPreviewApplyWords(item),
}))
.filter(item => item.applyWords.length > 0)
const groupedDetails = new Map<string, { sourceNames: string[]; orgString?: string; applyWords: string[] }>()
filteredPreviewItems.value.forEach(item => {
const applyWords = getPreviewApplyWords(item)
if (!applyWords.length) return
const sourceName = getFileName(item.source)
const orgString = item.org_string?.trim() || undefined
const detailKey = JSON.stringify(applyWords)
const existingDetail = groupedDetails.get(detailKey)
if (existingDetail) {
if (!existingDetail.sourceNames.includes(sourceName)) existingDetail.sourceNames.push(sourceName)
return
}
groupedDetails.set(detailKey, {
sourceNames: [sourceName],
orgString,
applyWords,
})
})
return [...groupedDetails.values()].map(detail => ({
sourceName:
detail.sourceNames.length > 1
? t('dialog.reorganize.customWordsSameRules', { count: detail.sourceNames.length })
: detail.sourceNames[0],
orgString: detail.sourceNames.length > 1 ? undefined : detail.orgString,
applyWords: detail.applyWords,
}))
})
const previewEpisodeFormatRuleDetails = computed(() => {
const episodeFormat = transferForm.episode_format?.trim()
if (!episodeFormat) return []
const rulePattern = episodeFormatRecommendState.rulePattern?.trim()
const isGeneratedEpisodeFormat =
Boolean(episodeFormatRecommendState.generatedFormat) &&
episodeFormatRecommendState.generatedFormat === episodeFormat
if (!isGeneratedEpisodeFormat || !episodeFormatRecommendState.ruleName) {
return [
{
sourceName: t('dialog.reorganize.episodeFormatManualInput'),
orgString: t('dialog.reorganize.episodeFormatFinal', {
format: episodeFormat,
}),
applyWords: [],
},
]
}
return [
{
sourceName: t('dialog.reorganize.episodeFormatRecommendRule', {
rule: episodeFormatRecommendState.ruleName,
}),
orgString: t('dialog.reorganize.episodeFormatFinal', {
format: episodeFormat,
}),
applyWords: rulePattern
? [
t('dialog.reorganize.episodeFormatRulePattern', {
pattern: rulePattern,
}),
]
: [],
},
]
})
const previewRecognitionDetails = computed(() => [
...previewCustomWordDetails.value,
...previewEpisodeFormatRuleDetails.value,
])
const previewRecognitionDetailTitle = computed(() => {
return previewCustomWordDetails.value.length
? t('dialog.reorganize.customWordsApplied')
: t('dialog.reorganize.episodeFormatRuleDetails')
})
// 是否需要拓宽窗口
@@ -700,6 +785,12 @@ const canRecommendEpisodeFormat = computed(() => {
)
})
const episodeFormatRecommendSelectionKey = computed(() => {
const sourceItem = episodeFormatRecommendSourceItem.value
if (sourceItem) return getFileItemKey(sourceItem)
return episodeFormatRecommendSelectedFileItems.value.map(item => getFileItemKey(item)).join('||')
})
const episodeFormatRecommendTooltip = computed(() => {
if (episodeFormatRecommendState.loading) return t('dialog.reorganize.episodeFormatRecommendLoading')
if (
@@ -716,14 +807,14 @@ const episodeFormatRecommendTooltip = computed(() => {
})
watch(
() => getFileItemKey(episodeFormatRecommendSourceItem.value),
sourceKey => {
episodeFormatRecommendSelectionKey,
() => {
transferForm.fileitem = episodeFormatRecommendSourceItem.value ?? ({} as FileItem)
if (!sourceKey) {
episodeFormatRecommendState.ruleName = undefined
episodeFormatRecommendState.sampleFile = undefined
episodeFormatRecommendState.lastMessage = undefined
}
episodeFormatRecommendState.ruleName = undefined
episodeFormatRecommendState.rulePattern = undefined
episodeFormatRecommendState.generatedFormat = undefined
episodeFormatRecommendState.sampleFile = undefined
episodeFormatRecommendState.lastMessage = undefined
},
{ immediate: true },
)
@@ -831,6 +922,8 @@ async function handleRecommendEpisodeFormat() {
transferForm.episode_format = data.episode_format
episodeFormatRecommendState.ruleName = data.rule_name
episodeFormatRecommendState.rulePattern = data.pattern
episodeFormatRecommendState.generatedFormat = data.episode_format
episodeFormatRecommendState.sampleFile = data.sample_file
episodeFormatRecommendState.lastMessage = data.message
@@ -1573,14 +1666,14 @@ onUnmounted(() => {
<span class="preview-overview-card__value">{{ previewEpisodeCountText }}</span>
</div>
</div>
<div v-if="previewCustomWordDetails.length" class="preview-custom-words">
<div v-if="previewRecognitionDetails.length" class="preview-custom-words">
<div class="preview-custom-words__title">
<VIcon icon="mdi-tag-text-outline" size="16" />
<span>{{ t('dialog.reorganize.customWordsApplied') }}</span>
<span>{{ previewRecognitionDetailTitle }}</span>
</div>
<div class="preview-custom-words__items">
<div
v-for="(detail, index) in previewCustomWordDetails"
v-for="(detail, index) in previewRecognitionDetails"
:key="`${detail.sourceName}-${index}`"
class="preview-custom-words__item"
>
@@ -1588,7 +1681,7 @@ onUnmounted(() => {
<div v-if="detail.orgString" class="preview-custom-words__original">
{{ detail.orgString }}
</div>
<div class="preview-custom-words__chips">
<div v-if="detail.applyWords.length" class="preview-custom-words__chips">
<VChip
v-for="(word, wordIndex) in detail.applyWords"
:key="`${word}-${wordIndex}`"

View File

@@ -2614,6 +2614,10 @@ export default {
episodeFormatRecommendFailed: 'Failed to generate episode format, please try again later',
episodeFormatRecommendRule: 'Matched Rule: {rule}',
episodeFormatRecommendSample: 'Sample File: {file}',
episodeFormatRuleDetails: 'Manual Episode Positioning Rule',
episodeFormatFinal: 'Final Episode Positioning: {format}',
episodeFormatManualInput: 'Manual Episode Positioning Input',
episodeFormatRulePattern: 'Rule Regex: {pattern}',
episodeOffset: 'Episode Offset',
episodeOffsetHint: 'Episode offset calculation, e.g. -10 or EP*2',
episodeOffsetPlaceholder: 'e.g. -10',
@@ -2644,7 +2648,8 @@ export default {
previewSeasonInfo: 'Season',
previewSeasonLabel: 'Season',
previewEpisodeCount: 'Episodes',
customWordsApplied: 'Recognition Word Details',
customWordsApplied: 'Custom Recognition Words Matched',
customWordsSameRules: '{count} files applied the same recognition words',
previewAfterColumn: 'After',
previewBeforeColumn: 'Before',
previewFileNameColumn: 'Filename',

View File

@@ -2567,6 +2567,10 @@ export default {
episodeFormatRecommendFailed: '集数定位生成失败,请稍后重试',
episodeFormatRecommendRule: '命中规则:{rule}',
episodeFormatRecommendSample: '样本文件:{file}',
episodeFormatRuleDetails: '手动整理集数定位规则',
episodeFormatFinal: '最终集数定位:{format}',
episodeFormatManualInput: '手动输入集数定位',
episodeFormatRulePattern: '规则正则:{pattern}',
episodeOffset: '集数偏移',
episodeOffsetHint: '集数偏移运算,如-10或EP*2',
episodeOffsetPlaceholder: '如-10',
@@ -2597,7 +2601,8 @@ export default {
previewSeasonInfo: '季信息',
previewSeasonLabel: '季',
previewEpisodeCount: '总集数',
customWordsApplied: '识别词应用详情',
customWordsApplied: '自定义识别词匹配中',
customWordsSameRules: '{count} 个文件应用相同识别词',
previewAfterColumn: '整理后',
previewBeforeColumn: '整理前',
previewFileNameColumn: '文件名',

View File

@@ -2568,6 +2568,10 @@ export default {
episodeFormatRecommendFailed: '集數定位生成失敗,請稍後重試',
episodeFormatRecommendRule: '命中規則:{rule}',
episodeFormatRecommendSample: '樣本文件:{file}',
episodeFormatRuleDetails: '手動整理集數定位規則',
episodeFormatFinal: '最終集數定位:{format}',
episodeFormatManualInput: '手動輸入集數定位',
episodeFormatRulePattern: '規則正則:{pattern}',
episodeOffset: '集數偏移',
episodeOffsetHint: '集數偏移運算,如-10或EP*2',
episodeOffsetPlaceholder: '如-10',
@@ -2598,7 +2602,8 @@ export default {
previewSeasonInfo: '季資訊',
previewSeasonLabel: '季',
previewEpisodeCount: '總集數',
customWordsApplied: '識別詞應用詳情',
customWordsApplied: '自定義識別詞匹配中',
customWordsSameRules: '{count} 個文件套用相同識別詞',
previewAfterColumn: '整理後',
previewBeforeColumn: '整理前',
previewFileNameColumn: '文件名',