mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-06 20:43:03 +08:00
feat: add batch AI reorganization support to Transfer History view
This commit is contained in:
@@ -460,7 +460,8 @@ export default {
|
||||
botSecret: 'Bot Secret',
|
||||
botSecretHint: 'WebSocket secret of the WeChat Work AI bot',
|
||||
botChatId: 'Default Target',
|
||||
botChatIdHint: 'Use user userid; for proactive group messages use group:chatid. Leave empty to notify known interacted users',
|
||||
botChatIdHint:
|
||||
'Use user userid; for proactive group messages use group:chatid. Leave empty to notify known interacted users',
|
||||
botChatIdPlaceholder: 'userid or group:chatid',
|
||||
botWsUrl: 'WebSocket URL',
|
||||
botWsUrlHint: 'WebSocket endpoint for the WeChat Work AI bot, usually the default value',
|
||||
@@ -1475,8 +1476,9 @@ export default {
|
||||
fanartEnableHint: 'Use image data from fanart.tv',
|
||||
fanartLang: 'Fanart Language',
|
||||
fanartLangHint: 'Set language preference for Fanart images, ordered by priority when multiple selected',
|
||||
recognizePluginFirst: "Prioritize Plugin Recognition",
|
||||
recognizePluginFirstHint: "Prioritize calling plugins for media recognition. If a plugin matches, native recognition will be skipped",
|
||||
recognizePluginFirst: 'Prioritize Plugin Recognition',
|
||||
recognizePluginFirstHint:
|
||||
'Prioritize calling plugins for media recognition. If a plugin matches, native recognition will be skipped',
|
||||
githubProxy: 'Github Acceleration Proxy',
|
||||
githubProxyPlaceholder: 'Leave empty for no proxy',
|
||||
githubProxyHint: 'Use proxy to accelerate Github access speed',
|
||||
@@ -1598,7 +1600,7 @@ export default {
|
||||
skipDesc: 'Skip scraping, this file will not be generated',
|
||||
missingOnlyDesc: 'Scrape only if missing, existing file remains unchanged',
|
||||
overwriteDesc: 'Always scrape, existing file will be overwritten',
|
||||
}
|
||||
},
|
||||
},
|
||||
site: {
|
||||
siteSync: 'Site Synchronization',
|
||||
@@ -2842,6 +2844,7 @@ export default {
|
||||
actions: {
|
||||
aiRedo: 'Assistant Organize',
|
||||
aiRedoPending: 'Assistant Organizing...',
|
||||
batchAiRedo: 'Assistant Batch Organize',
|
||||
redo: 'Reorganize',
|
||||
delete: 'Delete',
|
||||
batchRedo: 'Batch Reorganize',
|
||||
@@ -3265,7 +3268,8 @@ export default {
|
||||
infoDesc:
|
||||
'Completing site authentication unlocks site capabilities and some plugin permissions. This step is optional and can also be configured later from the user menu.',
|
||||
selectSiteHint: 'Choose a supported auth site and fill in the required credentials for that site',
|
||||
submitHint: 'When you click Next, the wizard will immediately validate against the selected auth site and save the current parameters on success.',
|
||||
submitHint:
|
||||
'When you click Next, the wizard will immediately validate against the selected auth site and save the current parameters on success.',
|
||||
siteConfigNotExist: 'Authentication site configuration does not exist',
|
||||
fieldRequired: 'Please enter {name}',
|
||||
},
|
||||
|
||||
@@ -2799,6 +2799,7 @@ export default {
|
||||
actions: {
|
||||
aiRedo: '智能助手整理',
|
||||
aiRedoPending: '智能助手整理中...',
|
||||
batchAiRedo: '智能助手批量整理',
|
||||
redo: '重新整理',
|
||||
delete: '删除',
|
||||
batchRedo: '批量重新整理',
|
||||
|
||||
@@ -2801,6 +2801,7 @@ export default {
|
||||
actions: {
|
||||
aiRedo: '智能助手整理',
|
||||
aiRedoPending: '智能助手整理中...',
|
||||
batchAiRedo: '智能助手批量整理',
|
||||
redo: '重新整理',
|
||||
delete: '刪除',
|
||||
batchRedo: '批量重新整理',
|
||||
|
||||
@@ -59,7 +59,7 @@ const aiRedoProgressDialog = ref(false)
|
||||
const aiRedoProgressActive = ref(false)
|
||||
const aiRedoProgressText = ref(t('transferHistory.actions.aiRedoPending'))
|
||||
const aiRedoProgressSSE = ref<any>(null)
|
||||
const aiRedoProgressHistoryId = ref<number>()
|
||||
const aiRedoProgressHistoryIds = ref<number[]>([])
|
||||
|
||||
// 重新整理IDS
|
||||
const redoIds = ref<number[]>([])
|
||||
@@ -374,6 +374,7 @@ async function removeSingle(deleteSrc: boolean, deleteDest: boolean) {
|
||||
|
||||
// 批量删除记录
|
||||
async function removeBatch(deleteSrc: boolean, deleteDest: boolean) {
|
||||
if (hasRunningAiRedo.value) return
|
||||
// 关闭弹窗
|
||||
deleteConfirmDialog.value = false
|
||||
// 总条数
|
||||
@@ -409,6 +410,7 @@ async function deleteConfirmHandler(deleteSrc: boolean, deleteDest: boolean) {
|
||||
|
||||
// 批量删除历史记录
|
||||
async function removeHistoryBatch() {
|
||||
if (hasRunningAiRedo.value) return
|
||||
if (selected.value.length === 0) return
|
||||
|
||||
// 清空当前操作记录
|
||||
@@ -421,6 +423,7 @@ async function removeHistoryBatch() {
|
||||
}
|
||||
// 批量重新整理
|
||||
async function retransferBatch() {
|
||||
if (hasRunningAiRedo.value) return
|
||||
if (selected.value.length === 0) return
|
||||
|
||||
// 清空当前操作记录
|
||||
@@ -462,15 +465,14 @@ function stopAiRedoProgress() {
|
||||
|
||||
// AI整理完成
|
||||
async function finishAiRedo(success: boolean, errorMessage?: string) {
|
||||
const historyId = aiRedoProgressHistoryId.value
|
||||
const historyIds = [...aiRedoProgressHistoryIds.value]
|
||||
const historyIdSet = new Set(historyIds)
|
||||
|
||||
stopAiRedoProgress()
|
||||
aiRedoProgressDialog.value = false
|
||||
aiRedoProgressHistoryId.value = undefined
|
||||
|
||||
if (historyId !== undefined) {
|
||||
aiRedoIds.value = aiRedoIds.value.filter(id => id !== historyId)
|
||||
}
|
||||
aiRedoProgressHistoryIds.value = []
|
||||
aiRedoIds.value = aiRedoIds.value.filter(id => !historyIdSet.has(id))
|
||||
selected.value = selected.value.filter(item => !historyIdSet.has(item.id))
|
||||
|
||||
await fetchData()
|
||||
|
||||
@@ -493,9 +495,14 @@ async function handleAiRedoProgressMessage(event: MessageEvent) {
|
||||
|
||||
// 开始监听整理进度
|
||||
function startAiRedoProgress(historyId: number, progressKey: string) {
|
||||
startAiRedoProgressBatch([historyId], progressKey)
|
||||
}
|
||||
|
||||
// 开始监听批量整理进度
|
||||
function startAiRedoProgressBatch(historyIds: number[], progressKey: string) {
|
||||
stopAiRedoProgress()
|
||||
|
||||
aiRedoProgressHistoryId.value = historyId
|
||||
aiRedoProgressHistoryIds.value = historyIds
|
||||
aiRedoProgressDialog.value = true
|
||||
aiRedoProgressActive.value = true
|
||||
aiRedoProgressText.value = t('transferHistory.actions.aiRedoPending')
|
||||
@@ -543,6 +550,44 @@ async function triggerAiRedo(item: TransferHistory) {
|
||||
}
|
||||
}
|
||||
|
||||
// 批量触发AI整理
|
||||
async function triggerBatchAiRedo() {
|
||||
if (!aiAgentEnabled.value) {
|
||||
$toast.error(t('transferHistory.aiRedoDisabled'))
|
||||
return
|
||||
}
|
||||
if (hasRunningAiRedo.value) return
|
||||
|
||||
const historyIds = [...new Set(selected.value.map(item => item.id))]
|
||||
if (historyIds.length === 0) return
|
||||
|
||||
aiRedoIds.value = [...new Set([...aiRedoIds.value, ...historyIds])]
|
||||
let progressStarted = false
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.post('history/transfer/ai-redo', {
|
||||
history_ids: historyIds,
|
||||
})
|
||||
|
||||
const progressKey = result.data?.progress_key
|
||||
const acceptedIds = (result.data?.history_ids as number[] | undefined) ?? historyIds
|
||||
|
||||
if (!result.success || !progressKey) {
|
||||
$toast.error(result.message || t('transferHistory.aiRedoFailed'))
|
||||
return
|
||||
}
|
||||
startAiRedoProgressBatch(acceptedIds, progressKey)
|
||||
selected.value = selected.value.filter(item => !acceptedIds.includes(item.id))
|
||||
progressStarted = true
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
$toast.error(t('transferHistory.aiRedoFailed'))
|
||||
} finally {
|
||||
if (!progressStarted) {
|
||||
aiRedoIds.value = aiRedoIds.value.filter(id => !historyIds.includes(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算下拉菜单
|
||||
function getDropdownItems(item: TransferHistory) {
|
||||
return [
|
||||
@@ -645,7 +690,7 @@ const historyDynamicIcon = computed(() => (selected.value.length > 0 ? 'mdi-chev
|
||||
const historyDynamicMenuItems = computed(() => {
|
||||
if (selected.value.length === 0) return undefined
|
||||
|
||||
return [
|
||||
const items: Array<{ titleKey: string; icon: string; action: () => void; color?: string }> = [
|
||||
{
|
||||
titleKey: 'dialog.transferQueue.title',
|
||||
icon: 'mdi-timer-sand-paused',
|
||||
@@ -653,22 +698,36 @@ const historyDynamicMenuItems = computed(() => {
|
||||
transferQueueDialog.value = true
|
||||
},
|
||||
},
|
||||
{
|
||||
titleKey: 'transferHistory.actions.batchRedo',
|
||||
icon: 'mdi-redo-variant',
|
||||
action: () => {
|
||||
retransferBatch()
|
||||
},
|
||||
},
|
||||
{
|
||||
titleKey: 'transferHistory.actions.batchDelete',
|
||||
icon: 'mdi-trash-can-outline',
|
||||
color: 'error',
|
||||
action: () => {
|
||||
removeHistoryBatch()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
if (!hasRunningAiRedo.value) {
|
||||
items.push(
|
||||
{
|
||||
titleKey: 'transferHistory.actions.batchAiRedo',
|
||||
icon: 'mdi-robot-outline',
|
||||
action: () => {
|
||||
triggerBatchAiRedo()
|
||||
},
|
||||
},
|
||||
{
|
||||
titleKey: 'transferHistory.actions.batchRedo',
|
||||
icon: 'mdi-redo-variant',
|
||||
action: () => {
|
||||
retransferBatch()
|
||||
},
|
||||
},
|
||||
{
|
||||
titleKey: 'transferHistory.actions.batchDelete',
|
||||
icon: 'mdi-trash-can-outline',
|
||||
color: 'error',
|
||||
action: () => {
|
||||
removeHistoryBatch()
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return items
|
||||
})
|
||||
|
||||
useDynamicButton({
|
||||
@@ -980,7 +1039,7 @@ onUnmounted(() => {
|
||||
<Teleport to="body" v-if="!appMode && route.path === '/history'">
|
||||
<div v-if="isRefreshed" class="compact-fab-stack compact-fab-stack--history">
|
||||
<VFab
|
||||
v-if="selected.length > 0"
|
||||
v-if="selected.length > 0 && !hasRunningAiRedo"
|
||||
icon="mdi-trash-can-outline"
|
||||
color="warning"
|
||||
variant="tonal"
|
||||
@@ -989,7 +1048,7 @@ onUnmounted(() => {
|
||||
@click="removeHistoryBatch"
|
||||
/>
|
||||
<VFab
|
||||
v-if="selected.length > 0"
|
||||
v-if="selected.length > 0 && !hasRunningAiRedo"
|
||||
icon="mdi-redo-variant"
|
||||
color="success"
|
||||
variant="tonal"
|
||||
@@ -997,6 +1056,15 @@ onUnmounted(() => {
|
||||
class="compact-fab compact-fab--secondary"
|
||||
@click="retransferBatch"
|
||||
/>
|
||||
<VFab
|
||||
v-if="selected.length > 0 && !hasRunningAiRedo"
|
||||
icon="mdi-robot-outline"
|
||||
color="info"
|
||||
variant="tonal"
|
||||
appear
|
||||
class="compact-fab compact-fab--secondary"
|
||||
@click="triggerBatchAiRedo"
|
||||
/>
|
||||
<VFab
|
||||
icon="mdi-timer-sand-paused"
|
||||
color="primary"
|
||||
|
||||
Reference in New Issue
Block a user