import { useState, useEffect } from 'react' import { View, Text, StyleSheet, ScrollView, Dimensions, Pressable, StatusBar as RNStatusBar, ActivityIndicator, Alert, } from 'react-native' import { StatusBar } from 'expo-status-bar' import { SafeAreaView } from 'react-native-safe-area-context' import { Image } from 'expo-image' import { useRouter, useLocalSearchParams } from 'expo-router' import { LeftArrowIcon, DeleteIcon, EditIcon, ChangeIcon, WhiteStarIcon } from '@/components/icon' import { useTemplateGenerationDetail } from '@/hooks/data/use-template-generation-detail' import { useTemplateActions } from '@/hooks/actions/use-template-actions' import { useAigcTask } from '@/hooks/actions/use-aigc-task' import { useUserBalance } from '@/hooks/core/use-user-balance' import { useAuth } from '@/hooks/core/use-auth' const { width: screenWidth } = Dimensions.get('window') const CREDITS_COST = 10 export default function GenerationRecordScreen() { const router = useRouter() const params = useLocalSearchParams() const { user } = useAuth() const { balance, load: loadBalance } = useUserBalance() const generationId = params.id as string const { data: generation, loading, load, refetch } = useTemplateGenerationDetail() const { deleteGeneration, runTemplate, createGeneration } = useTemplateActions() const { submitTask, startPolling, stopPolling } = useAigcTask() const [isRegenerating, setIsRegenerating] = useState(false) const [isDeleting, setIsDeleting] = useState(false) useEffect(() => { if (generationId) { load({ id: generationId }) } }, [generationId]) useEffect(() => { if (user?.id) { loadBalance(user.id) } }, [user?.id]) useEffect(() => { return () => { stopPolling() } }, []) const handleRegenerate = async () => { if (!generation) return if (balance < CREDITS_COST) { Alert.alert('积分不足', `生成视频需要 ${CREDITS_COST} 积分,当前积分:${balance}`) return } setIsRegenerating(true) const { taskId, error: submitError } = await submitTask({ model_name: 'video_generation', prompt: '再次生成', img_url: generation.originalUrl || '', duration: '3', resolution: '720p', watermark: false, webhook_flag: false, }) if (submitError) { Alert.alert('生成失败', submitError.message || '提交任务失败') setIsRegenerating(false) return } if (!taskId) { Alert.alert('生成失败', '任务ID获取失败') setIsRegenerating(false) return } startPolling( taskId, async (result) => { const videoUrls = result.data || [] const { generation: newGeneration, error: createError } = await createGeneration({ templateId: generation.templateId, type: 'VIDEO', resultUrl: videoUrls, originalUrl: generation.originalUrl || '', status: 'completed', creditsCost: CREDITS_COST, }) if (createError) { Alert.alert('保存失败', createError.message || '生成记录保存失败') } else { Alert.alert('生成成功', '视频已生成完成') if (user?.id) { loadBalance(user.id) } if (newGeneration?.id) { router.replace({ pathname: '/generationRecord' as any, params: { id: newGeneration.id }, }) } } setIsRegenerating(false) }, (error) => { Alert.alert('生成失败', error.message || '视频生成失败') setIsRegenerating(false) } ) } const handleEdit = () => { if (!generation) return router.push({ pathname: '/generateVideo' as any, params: { template: JSON.stringify({ id: generation.templateId, title: 'AI 视频', thumbnailUrl: generation.originalUrl, duration: '3', }), }, }) } const handleDelete = async () => { if (!generationId) return Alert.alert('确认删除', '确定要删除这条生成记录吗?', [ { text: '取消', style: 'cancel' }, { text: '删除', style: 'destructive', onPress: async () => { setIsDeleting(true) const { success, error } = await deleteGeneration(generationId) if (error) { Alert.alert('删除失败', error.message || '删除失败,请重试') setIsDeleting(false) } else { Alert.alert('删除成功', '生成记录已删除', [ { text: '确定', onPress: () => router.back(), }, ]) } }, }, ]) } const resultUrl = generation?.resultUrl?.[0] || generation?.originalUrl const isLoading = loading || isRegenerating || isDeleting return ( {/* 顶部导航栏 */} router.back()} > 生成记录 {/* AI 视频标签 */} AI 视频 {/* 原图标签 */} 原图 {/* 主图片/视频预览区域 */} {loading ? ( ) : resultUrl ? ( ) : ( 暂无预览 )} {generation?.createdAt ? new Date(generation.createdAt).toLocaleString('zh-CN') : ''} {/* 底部操作按钮 */} 重新编辑 {isRegenerating ? ( ) : ( <> 再次生成 )} {isDeleting ? ( ) : ( )} ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#090A0B', }, scrollView: { flex: 1, backgroundColor: '#090A0B', }, scrollContent: { paddingBottom: 100, backgroundColor: '#090A0B', }, header: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 12, paddingTop: 16, paddingBottom: 20, }, backButton: { width: 22, height: 22, alignItems: 'center', justifyContent: 'center', }, headerTitle: { color: '#F5F5F5', fontSize: 14, fontWeight: '600', flex: 1, textAlign: 'center', }, headerSpacer: { width: 22, }, categorySection: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, marginBottom: 8, gap:4, }, categoryIcon: { width: 16, height: 16, alignItems: 'center', justifyContent: 'center', }, categoryText: { color: '#F5F5F5', fontSize: 14, fontWeight: '600', }, originalImageSection: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, marginBottom: 8, }, originalImageLabel: { color: '#8A8A8A', fontSize: 13, marginRight: 6, }, originalImageDivider: { width: 1, height: 12, backgroundColor: '#FFFFFF33', }, imageContainer: { width: screenWidth - 24, height: (screenWidth - 24) * 1.32, // 根据设计稿比例计算 marginHorizontal: 12, marginBottom: 14, borderRadius: 16, overflow: 'hidden', backgroundColor: '#1C1E22', position: 'relative', }, mainImage: { width: '100%', height: '100%', }, durationText: { paddingLeft: 28, color: '#F5F5F5', fontSize: 13, marginBottom: 22, fontWeight: '500', }, actionButtons: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 12, gap: 8, }, actionButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingHorizontal: 8, paddingVertical: 6, borderRadius: 8, backgroundColor: '#1C1E22', height: 32, }, actionButtonText: { color: '#F5F5F5', fontSize: 11, fontWeight: '500', }, deleteButton: { width: 32, height: 32, borderRadius: 8, backgroundColor: '#1C1E22', alignItems: 'center', justifyContent: 'center', marginLeft: 'auto', }, buttonDisabled: { opacity: 0.5, }, loadingContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', }, placeholderContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', }, placeholderText: { color: '#8A8A8A', fontSize: 14, }, })