feat: 支持重新评估历史视频,前端显示视频的规则评估状态 (#465)
This commit is contained in:
@@ -4,6 +4,16 @@
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@layer utilities {
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth !important;
|
||||
}
|
||||
|
||||
@@ -217,6 +217,10 @@ class ApiClient {
|
||||
return this.put<UpdateVideoSourceResponse>(`/video-sources/${type}/${id}`, request);
|
||||
}
|
||||
|
||||
async evaluateVideoSourceRules(type: string, id: number): Promise<ApiResponse<boolean>> {
|
||||
return this.post<boolean>(`/video-sources/${type}/${id}/evaluate`, null);
|
||||
}
|
||||
|
||||
async getConfig(): Promise<ApiResponse<Config>> {
|
||||
return this.get<Config>('/config');
|
||||
}
|
||||
@@ -262,6 +266,8 @@ const api = {
|
||||
getVideoSourcesDetails: () => apiClient.getVideoSourcesDetails(),
|
||||
updateVideoSource: (type: string, id: number, request: UpdateVideoSourceRequest) =>
|
||||
apiClient.updateVideoSource(type, id, request),
|
||||
evaluateVideoSourceRules: (type: string, id: number) =>
|
||||
apiClient.evaluateVideoSourceRules(type, id),
|
||||
getConfig: () => apiClient.getConfig(),
|
||||
updateConfig: (config: Config) => apiClient.updateConfig(config),
|
||||
getDashboard: () => apiClient.getDashboard(),
|
||||
|
||||
@@ -49,20 +49,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getOverallStatus(downloadStatus: number[]): {
|
||||
function getOverallStatus(
|
||||
downloadStatus: number[],
|
||||
shouldDownload: boolean
|
||||
): {
|
||||
text: string;
|
||||
color: 'default' | 'secondary' | 'destructive' | 'outline';
|
||||
style: string;
|
||||
} {
|
||||
if (!shouldDownload) {
|
||||
// 被筛选规则排除,显示为“跳过”
|
||||
return { text: '跳过', style: 'bg-gray-100 text-gray-700' };
|
||||
}
|
||||
const completed = downloadStatus.filter((status) => status === 7).length;
|
||||
const total = downloadStatus.length;
|
||||
const failed = downloadStatus.filter((status) => status !== 7 && status !== 0).length;
|
||||
|
||||
if (completed === total) {
|
||||
return { text: '完成', color: 'outline' };
|
||||
// 全部完成,显示为“完成”
|
||||
return { text: '完成', style: 'bg-emerald-700 text-emerald-100' };
|
||||
} else if (failed > 0) {
|
||||
return { text: '失败', color: 'destructive' };
|
||||
// 出现了失败,显示为“失败”
|
||||
return { text: '失败', style: 'bg-rose-700 text-rose-100' };
|
||||
} else {
|
||||
return { text: '进行中', color: 'secondary' };
|
||||
// 还未开始,显示为“等待”
|
||||
return { text: '等待', style: 'bg-yellow-700 text-yellow-100' };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +84,7 @@
|
||||
return defaultTaskNames[index] || `任务${index + 1}`;
|
||||
}
|
||||
|
||||
$: overallStatus = getOverallStatus(video.download_status);
|
||||
$: overallStatus = getOverallStatus(video.download_status, video.should_download);
|
||||
$: completed = video.download_status.filter((status) => status === 7).length;
|
||||
$: total = video.download_status.length;
|
||||
|
||||
@@ -112,7 +122,10 @@
|
||||
>
|
||||
{displayTitle}
|
||||
</CardTitle>
|
||||
<Badge variant={overallStatus.color} class="shrink-0 px-2 py-1 text-xs font-medium">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
class="shrink-0 px-2 py-1 text-xs font-medium {overallStatus.style} "
|
||||
>
|
||||
{overallStatus.text}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface VideoInfo {
|
||||
bvid: string;
|
||||
name: string;
|
||||
upper_name: string;
|
||||
should_download: boolean;
|
||||
download_status: [number, number, number, number, number];
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
import type { ApiError, VideoSourceDetail, VideoSourcesDetailsResponse, Rule } from '$lib/types';
|
||||
import api from '$lib/api';
|
||||
import RuleEditor from '$lib/components/rule-editor.svelte';
|
||||
import ListRestartIcon from '@lucide/svelte/icons/list-restart';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js';
|
||||
|
||||
let videoSourcesData: VideoSourcesDetailsResponse | null = null;
|
||||
let loading = false;
|
||||
@@ -36,6 +38,12 @@
|
||||
let editingIdx: number = 0;
|
||||
let saving = false;
|
||||
|
||||
// 规则评估对话框状态
|
||||
let showEvaluateDialog = false;
|
||||
let evaluateSource: VideoSourceDetail | null = null;
|
||||
let evaluateType = '';
|
||||
let evaluating = false;
|
||||
|
||||
// 编辑表单数据
|
||||
let editForm = {
|
||||
path: '',
|
||||
@@ -83,6 +91,12 @@
|
||||
showEditDialog = true;
|
||||
}
|
||||
|
||||
function openEvaluateRules(type: string, source: VideoSourceDetail) {
|
||||
evaluateSource = source;
|
||||
evaluateType = type;
|
||||
showEvaluateDialog = true;
|
||||
}
|
||||
|
||||
// 保存编辑
|
||||
async function saveEdit() {
|
||||
if (!editingSource) return;
|
||||
@@ -91,7 +105,6 @@
|
||||
toast.error('路径不能为空');
|
||||
return;
|
||||
}
|
||||
|
||||
saving = true;
|
||||
try {
|
||||
let response = await api.updateVideoSource(editingType, editingSource.id, {
|
||||
@@ -99,7 +112,6 @@
|
||||
enabled: editForm.enabled,
|
||||
rule: editForm.rule
|
||||
});
|
||||
|
||||
// 更新本地数据
|
||||
if (videoSourcesData && editingSource) {
|
||||
const sources = videoSourcesData[
|
||||
@@ -114,7 +126,6 @@
|
||||
};
|
||||
videoSourcesData = { ...videoSourcesData };
|
||||
}
|
||||
|
||||
showEditDialog = false;
|
||||
toast.success('保存成功');
|
||||
} catch (error) {
|
||||
@@ -126,6 +137,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function evaluateRules() {
|
||||
if (!evaluateSource) return;
|
||||
evaluating = true;
|
||||
try {
|
||||
let response = await api.evaluateVideoSourceRules(evaluateType, evaluateSource.id);
|
||||
if (response && response.data) {
|
||||
showEvaluateDialog = false;
|
||||
toast.success('重新评估规则成功');
|
||||
} else {
|
||||
toast.error('重新评估规则失败');
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('重新评估规则失败', {
|
||||
description: (error as ApiError).message
|
||||
});
|
||||
} finally {
|
||||
evaluating = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getSourcesForTab(tabValue: string): VideoSourceDetail[] {
|
||||
if (!videoSourcesData) return [];
|
||||
return videoSourcesData[tabValue as keyof VideoSourcesDetailsResponse] as VideoSourceDetail[];
|
||||
@@ -288,6 +319,15 @@
|
||||
>
|
||||
<EditIcon class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onclick={() => openEvaluateRules(key, source)}
|
||||
class="h-8 w-8 p-0"
|
||||
title="重新评估规则"
|
||||
>
|
||||
<ListRestartIcon class="h-3 w-3" />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
@@ -330,7 +370,9 @@
|
||||
|
||||
<!-- 编辑对话框 -->
|
||||
<Dialog.Root bind:open={showEditDialog}>
|
||||
<Dialog.Content class="max-h-[85vh] w-4xl !max-w-none overflow-y-auto">
|
||||
<Dialog.Content
|
||||
class="no-scrollbar max-h-[85vh] !max-w-[90vw] overflow-y-auto lg:!max-w-[70vw]"
|
||||
>
|
||||
<Dialog.Title class="text-lg font-semibold">
|
||||
编辑视频源: {editingSource?.name || ''}
|
||||
</Dialog.Title>
|
||||
@@ -369,6 +411,31 @@
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<AlertDialog.Root bind:open={showEvaluateDialog}>
|
||||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title>重新评估规则</AlertDialog.Title>
|
||||
<AlertDialog.Description>
|
||||
确定要重新评估视频源 <strong>"{evaluateSource?.name}"</strong> 的筛选规则吗?<br />
|
||||
规则修改后默认仅对新视频生效,该操作可使用当前规则对数据库中已存在的历史视频进行重新评估,<span
|
||||
class="text-destructive font-medium">无法撤销</span
|
||||
>。<br />
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Cancel
|
||||
disabled={evaluating}
|
||||
onclick={() => {
|
||||
showEvaluateDialog = false;
|
||||
}}>取消</AlertDialog.Cancel
|
||||
>
|
||||
<AlertDialog.Action onclick={evaluateRules} disabled={evaluating}>
|
||||
{evaluating ? '重新评估中' : '确认重新评估'}
|
||||
</AlertDialog.Action>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
|
||||
<!-- 添加对话框 -->
|
||||
<Dialog.Root bind:open={showAddDialog}>
|
||||
<Dialog.Content>
|
||||
|
||||
@@ -156,7 +156,8 @@
|
||||
bvid: videoData.video.bvid,
|
||||
name: videoData.video.name,
|
||||
upper_name: videoData.video.upper_name,
|
||||
download_status: videoData.video.download_status
|
||||
download_status: videoData.video.download_status,
|
||||
should_download: videoData.video.should_download
|
||||
}}
|
||||
mode="detail"
|
||||
showActions={false}
|
||||
@@ -209,7 +210,8 @@
|
||||
id: pageInfo.id,
|
||||
name: `P${pageInfo.pid}: ${pageInfo.name}`,
|
||||
upper_name: '',
|
||||
download_status: pageInfo.download_status
|
||||
download_status: pageInfo.download_status,
|
||||
should_download: videoData.video.should_download
|
||||
}}
|
||||
mode="page"
|
||||
showActions={false}
|
||||
|
||||
Reference in New Issue
Block a user