fix
This commit is contained in:
parent
2c609c04f1
commit
1435c72ba6
|
|
@ -1,14 +1,23 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { Link, useLocation } from 'react-router-dom'
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
import { Home, Video, Settings, FolderOpen, Music, Image, Sparkles, List, Play, Clock, CheckCircle, XCircle, Layout } from 'lucide-react'
|
import { Home, Video, Settings, FolderOpen, Music, Image, Sparkles, Layout, Clock, CheckCircle, XCircle, List } from 'lucide-react'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { useAIVideoJobs } from '../stores/useAIVideoStore'
|
|
||||||
|
|
||||||
const Sidebar: React.FC = () => {
|
const Sidebar: React.FC = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const jobs = useAIVideoJobs()
|
|
||||||
const [activeTab, setActiveTab] = useState<'nav' | 'tasks'>('nav')
|
const [activeTab, setActiveTab] = useState<'nav' | 'tasks'>('nav')
|
||||||
|
|
||||||
|
// Mock jobs data - this should be replaced with actual state management
|
||||||
|
const jobs: Array<{
|
||||||
|
id: string
|
||||||
|
type: 'single' | 'batch'
|
||||||
|
status: 'processing' | 'completed' | 'failed'
|
||||||
|
progress: number
|
||||||
|
startTime: number
|
||||||
|
result?: { success_count?: number }
|
||||||
|
error?: string
|
||||||
|
}> = []
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ path: '/', icon: Home, label: '首页' },
|
{ path: '/', icon: Home, label: '首页' },
|
||||||
{ path: '/editor', icon: Video, label: '编辑器' },
|
{ path: '/editor', icon: Video, label: '编辑器' },
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,38 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { Sparkles, Info, Settings, HelpCircle, TestTube } from 'lucide-react'
|
import { Sparkles, Info, Settings, HelpCircle, List, BookOpen } from 'lucide-react'
|
||||||
import AIVideoGenerator from '../components/AIVideoGenerator'
|
import AIVideoGenerator from '../components/AIVideoGenerator'
|
||||||
import { AIVideoService } from '../services/tauri'
|
import VideoJobList from '../components/ai-video/VideoJobList'
|
||||||
|
import { useAIVideoStore } from '../stores/useAIVideoStore'
|
||||||
|
|
||||||
const AIVideoPage: React.FC = () => {
|
const AIVideoPage: React.FC = () => {
|
||||||
const [testResult, setTestResult] = useState<any>(null)
|
const [activeTab, setActiveTab] = useState<'tasks' | 'guide'>('tasks')
|
||||||
const [isTesting, setIsTesting] = useState(false)
|
|
||||||
|
|
||||||
const handleTestEnvironment = async () => {
|
// Get jobs from store
|
||||||
setIsTesting(true)
|
const jobs = useAIVideoStore(state => state.jobs)
|
||||||
setTestResult(null)
|
const removeJob = useAIVideoStore(state => state.removeJob)
|
||||||
|
const generateSingleVideo = useAIVideoStore(state => state.generateSingleVideo)
|
||||||
|
const batchGenerateVideos = useAIVideoStore(state => state.batchGenerateVideos)
|
||||||
|
|
||||||
|
// Job handlers
|
||||||
|
const handlePreviewJob = (job: any) => {
|
||||||
|
// TODO: Implement job preview
|
||||||
|
console.log('Preview job:', job)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteJob = (jobId: string) => {
|
||||||
|
removeJob(jobId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRetryJob = async (job: any) => {
|
||||||
try {
|
try {
|
||||||
const result = await AIVideoService.testEnvironment()
|
if (job.type === 'single') {
|
||||||
setTestResult(result)
|
await generateSingleVideo(job.request)
|
||||||
console.log('Environment test result:', result)
|
} else if (job.type === 'batch') {
|
||||||
|
await batchGenerateVideos(job.request)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setTestResult({
|
console.error('Retry failed:', error)
|
||||||
status: 'error',
|
alert(`重试失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
||||||
error: error instanceof Error ? error.message : String(error)
|
|
||||||
})
|
|
||||||
console.error('Environment test failed:', error)
|
|
||||||
} finally {
|
|
||||||
setIsTesting(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +72,53 @@ const AIVideoPage: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<div className="w-64 bg-white border-l border-secondary-200 p-6 overflow-y-auto">
|
<div className="w-80 bg-white border-l border-secondary-200 flex flex-col">
|
||||||
|
{/* Tab Headers */}
|
||||||
|
<div className="border-b border-secondary-200">
|
||||||
|
<div className="flex">
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('tasks')}
|
||||||
|
className={`flex-1 px-4 py-3 text-sm font-medium border-b-2 transition-colors flex items-center justify-center gap-2 ${
|
||||||
|
activeTab === 'tasks'
|
||||||
|
? 'border-primary-500 text-primary-600 bg-primary-50'
|
||||||
|
: 'border-transparent text-secondary-600 hover:text-secondary-900 hover:bg-secondary-50'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<List size={16} />
|
||||||
|
任务列表
|
||||||
|
{jobs.length > 0 && (
|
||||||
|
<span className="bg-primary-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
|
||||||
|
{jobs.length}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('guide')}
|
||||||
|
className={`flex-1 px-4 py-3 text-sm font-medium border-b-2 transition-colors flex items-center justify-center gap-2 ${
|
||||||
|
activeTab === 'guide'
|
||||||
|
? 'border-primary-500 text-primary-600 bg-primary-50'
|
||||||
|
: 'border-transparent text-secondary-600 hover:text-secondary-900 hover:bg-secondary-50'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<BookOpen size={16} />
|
||||||
|
使用说明
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tab Content */}
|
||||||
|
<div className="flex-1 overflow-hidden">
|
||||||
|
{activeTab === 'tasks' ? (
|
||||||
|
<div className="h-full p-4">
|
||||||
|
<VideoJobList
|
||||||
|
jobs={jobs}
|
||||||
|
onPreview={handlePreviewJob}
|
||||||
|
onDelete={handleDeleteJob}
|
||||||
|
onRetry={handleRetryJob}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="h-full p-6 overflow-y-auto">
|
||||||
<h3 className="text-lg font-semibold text-secondary-900 mb-4">使用说明</h3>
|
<h3 className="text-lg font-semibold text-secondary-900 mb-4">使用说明</h3>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
|
@ -203,6 +259,9 @@ const AIVideoPage: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const TemplateManagePage: React.FC = () => {
|
||||||
const handleBatchImport = async () => {
|
const handleBatchImport = async () => {
|
||||||
try {
|
try {
|
||||||
// Select folder using Tauri dialog
|
// Select folder using Tauri dialog
|
||||||
const folderResult = await invoke('select_folder')
|
const folderResult = await invoke<string>('select_folder')
|
||||||
if (!folderResult) return
|
if (!folderResult) return
|
||||||
|
|
||||||
setImporting(true)
|
setImporting(true)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue