You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

12 KiB

清理预览区域 Mock 数据(完整版)

日期: 2026-02-08
类型: 代码清理 + Bug 修复
影响范围: 前端预览面板

概述

移除预览面板中所有的 mock 数据,确保只使用真实的 API 数据。同时修复了"正视图、侧视图、背视图"这些假数据的显示问题。

🐛 核心问题

问题描述: 点击角色资源时,预览区域显示的是"正视图、侧视图、背视图",这些是 mock 数据,而不是真实的标签数据。

根本原因:

// 错误逻辑:当没有标签时,生成假的"正视图、侧视图、背视图"
if (resource.type === 1) {
  if (hasTags) {
    return tags.map(...); // 显示真实标签
  }
  
  // ❌ 没有标签时,返回假数据
  return [
    { title: '孙悟空 (正视图)', ... },
    { title: '孙悟空 (侧视图)', ... },
    { title: '孙悟空 (背视图)', ... },
  ];
}

正确逻辑:

// ✅ 有标签 → 显示标签
// ✅ 没有标签 → 返回空数组,显示"暂无标签"空状态
if (resource.type === 1) {
  if (hasTags) {
    return tags.map(...); // 显示真实标签
  }
  return []; // 没有标签时返回空数组
}

清理内容

已清理的 Mock 数据

1. AI 生成功能的假数据 (usePreviewActions.ts)

清理前:

// 随机获取一张 Unsplash 图片作为生成结果
const mockGeneratedUrl = `https://images.unsplash.com/photo-${...}?w=800&q=80`;

if (isTagItem && tags) {
  updatedTags[index] = {
    ...updatedTags[index],
    thumbnail_url: mockGeneratedUrl, // ❌ 假数据
  };
}

清理后:

toast({
  title: 'AI 生成功能未实现',
  description: `需要接入真实的 AI 生成 API 为 "${targetName}" 生成图片`,
  variant: 'destructive',
});

// TODO: 接入真实的 AI 生成 API
// 1. 调用后端 AI 生成接口
// 2. 等待生成完成
// 3. 更新资源/标签的图片URL

2. 视频数据 Mock (usePreviewData.ts)

清理前:

import { mockStoryboardVideos } from '@/mocks';
// ...
const storyboardVideos = mockStoryboardVideos.filter((v) => v.storyboardId === storyboardId);

清理后:

// 移除 import
// ...
// 获取该分镜下的所有视频 (TODO: 使用真实API替换)
const storyboardVideos: any[] = []; // 临时置空,等待视频API实现

说明: 后端已有视频API (server/app/api/v1/storyboard_resources.py::get_storyboard_videos),但前端尚未实现对应的 Hook,需要后续添加 useStoryboardVideos().

3. 音效数据 Mock (SoundEffectPreview.tsx)

清理前:

import { mockStoryboardSoundEffects } from '@/mocks/storyboard-sound-effects';
// ...
return mockStoryboardSoundEffects.filter((e) => e.storyboardId === storyboardId);

清理后:

// 移除 import
// ...
const effects = useMemo(() => {
  // TODO: 使用真实的音效API
  // return useSoundEffects(storyboardId);
  if (!storyboardId) return [];
  return []; // 临时置空,等待音效API实现
}, [storyboardId]);

4. 资源标签和档案 Mock (ResourceInfoPanel.tsx)

清理前:

import {
  mockCharacterTags,
  mockLocationVariantTags,
  mockPropTags,
  mockTagCategories,
  mockProfiles,
} from '@/mocks';

// Mock tags data
const tags: Tag[] = useMemo(() => {
  if (resourceType === 1) return mockCharacterTags;
  if (resourceType === 2) return mockLocationVariantTags;
  if (resourceType === 3) return mockPropTags;
  return [];
}, [resourceType, resourceId]);

// Mock profile data
const mockData = mockProfiles[typeStr];
return mockData ? { ...mockData, name: resourceName, type: typeStr } : {...};

清理后:

// 移除所有 mock imports

// TODO: 从真实API获取标签数据
const tags: Tag[] = useMemo(() => {
  if (!resourceType || !resourceId) return [];
  // 应该从 useCharacterDetail / useLocationDetail / usePropDetail 获取
  return [];
}, [resourceType, resourceId]);

// TODO: 从真实API获取资源档案数据
const profileData = useMemo(() => {
  // 应该从 useCharacterDetail / useLocationDetail / usePropDetail 获取
  return {
    type: typeStr,
    name: resourceName,
    description: '',
  };
}, [resourceType, resourceName]);

// 标签分类也改为空数组
<ResourceTagsTab
  categories={[]} // TODO: 从真实API获取标签分类
/>

说明: ResourceInfoPanel 目前未被 PreviewPanel 使用,但仍清理干净以备未来使用。

⚠️ 保留的临时逻辑

以下代码暂时保留空数组,等待对应的真实API实现:

  1. 视频列表: const storyboardVideos: any[] = [];

    • 需要实现: useStoryboardVideos(storyboardId)
    • 后端API: GET /api/v1/storyboard-resources/{storyboardId}/videos
  2. 音效列表: return [];

    • 需要实现: useSoundEffects(storyboardId)
    • 后端API: (需确认是否存在)
  3. 标签分类: categories={[]}

    • 需要实现: useTagCategories(projectId, resourceType)
    • 后端API: (需确认是否存在)

清理后的数据流

当前可用的功能 (使用真实API)

用户点击角色/场景/道具
  ↓
useCharacterDetail / useLocationDetail / usePropDetail
  ↓
GET /projects/{projectId}/characters/{characterId}
  ↓
返回真实的角色+标签+资源数据
  ↓
PreviewPanel 显示真实的缩略图和标签

待实现的功能

  1. 视频预览

    用户点击分镜中的视频元素
      ↓
    useStoryboardVideos(storyboardId) // TODO: 需实现
      ↓
    GET /api/v1/storyboard-resources/{storyboardId}/videos
      ↓
    显示真实视频列表
    
  2. 音效预览

    用户切换到音效标签
      ↓
    useSoundEffects(storyboardId) // TODO: 需实现
      ↓
    GET /api/v1/storyboard-resources/{storyboardId}/sound-effects (?)
      ↓
    显示真实音效列表
    
  3. AI 生成图片

    用户点击"生成"按钮
      ↓
    调用 AI 生成 API // TODO: 需实现
      ↓
    POST /api/v1/ai/generate-image (?)
      ↓
    更新资源/标签的图片URL
    

影响分析

功能影响

  • 角色/场景/道具预览: 正常工作,使用真实API
  • ⚠️ 视频预览: 暂时显示空列表,不影响其他功能
  • ⚠️ 音效预览: 暂时显示空列表,不影响其他功能
  • AI 生成: 点击按钮会提示"功能未实现",不会再生成假数据

用户体验

改进:

  • 不再显示误导性的假数据
  • 用户看到的都是真实的项目数据

降级:

  • 视频和音效预览暂时为空 (但这些功能本来就未完全实现)
  • AI 生成按钮暂时不可用 (但之前生成的也是假数据)

后续任务

高优先级 (影响核心功能)

  1. 实现视频 Hook

    // client/src/hooks/api/useStoryboardVideos.ts
    export function useStoryboardVideos(storyboardId: string | null) {
      return useQuery({
        queryKey: ['storyboard-videos', storyboardId],
        queryFn: () => storyboardVideosApi.getVideos(storyboardId!),
        enabled: !!storyboardId,
      });
    }
    
  2. 实现音效 Hook

    // client/src/hooks/api/useSoundEffects.ts
    export function useSoundEffects(storyboardId: string | null) {
      return useQuery({
        queryKey: ['sound-effects', storyboardId],
        queryFn: () => soundEffectsApi.getSoundEffects(storyboardId!),
        enabled: !!storyboardId,
      });
    }
    

中优先级 (增强用户体验)

  1. 实现 AI 生成图片功能

    • 后端: 接入真实的 AI 图片生成服务 (如 Stable Diffusion, DALL-E)
    • 前端: 调用生成API,显示进度,更新图片
  2. 实现标签分类管理

    • 后端: 标签分类的CRUD API
    • 前端: useTagCategories() Hook

低优先级 (可选)

  1. 完善 ResourceInfoPanel
    • 集成真实的资源详情数据
    • 显示完整的资源档案信息

验证方法

1. 测试有标签的资源

1. 在后端创建一个角色,并添加标签 (如"便装"、"战斗装")
2. 在前端点击该角色
3. 预览面板应该显示:
   ✅ "孙悟空 - 便装" (标签1)
   ✅ "孙悟空 - 战斗装" (标签2)
   ❌ 不应该显示"正视图、侧视图、背视图"

2. 测试没有标签的资源

1. 在后端创建一个角色,不添加任何标签
2. 在前端点击该角色
3. 预览面板应该显示:
   ✅ 空状态提示 (如"暂无标签"或"No items to display")
   ❌ 不应该显示"正视图、侧视图、背视图"

3. 检查控制台是否有 mock 相关的警告

cd client
npm run dev
# 打开浏览器控制台,检查是否有 "mock" 相关的日志

4. 搜索代码中是否还有 mock 导入

cd client/src/components/features/preview
rg "from.*@/mocks" --type ts
rg "from.*mocks" --type ts
rg "mockStoryboard|mockCharacter|mockLocation|mockProp" --type ts

预期结果: 只在以下文件中保留 mock (非预览核心功能):

  • HistoryPanel.tsx (历史记录面板,目前完全是mock UI)
  • ResourceProfileTab.tsx (配音选择,使用 mockVoices)
  • VoiceSelectionDialog.tsx (配音选择,使用 mockVoices)
  • StoryboardResourcesPreview.tsx (一条 Mock 逻辑注释)

5. 测试空状态显示

  1. 打开项目页面
  2. 切换到"角色"标签
  3. 点击一个没有标签的角色
  4. 预览面板应该显示:
    • 空状态组件 (EmptyState)
    • 提示文字 (如"No items to display")
    • 不应该有"正视图、侧视图、背视图"

对比图

清理前 ( 错误)

点击"孙悟空"角色 (无标签)
  ↓
预览面板显示:
  - 孙悟空 (正视图) ← ❌ 假数据
  - 孙悟空 (侧视图) ← ❌ 假数据  
  - 孙悟空 (背视图) ← ❌ 假数据

清理后 ( 正确)

点击"孙悟空"角色 (无标签)
  ↓
预览面板显示:
  - "暂无标签" 空状态 ← ✅ 真实状态

点击"孙悟空"角色 (有标签)
  ↓
预览面板显示:
  - 孙悟空 - 便装 ← ✅ 真实标签
  - 孙悟空 - 战斗装 ← ✅ 真实标签

测试角色创建流程

1. 创建带标签的角色

# 后端测试脚本
curl -X POST http://localhost:8000/api/v1/projects/{projectId}/characters \
  -H "Content-Type: application/json" \
  -d '{
    "name": "测试角色",
    "description": "用于测试标签显示",
    "role_type": 2,
    "tags": ["便装", "战斗装"]
  }'

预期:

  • 前端点击该角色,预览面板显示2个标签
  • 不显示"正视图、侧视图、背视图"

2. 创建无标签的角色

curl -X POST http://localhost:8000/api/v1/projects/{projectId}/characters \
  -H "Content-Type: application/json" \
  -d '{
    "name": "测试角色2",
    "description": "无标签角色",
    "role_type": 2
  }'

预期:

  • 前端点击该角色,预览面板显示空状态
  • 不显示"正视图、侧视图、背视图"

3. 测试资源预览

  1. 打开项目页面
  2. 切换到"角色"标签
  3. 点击任意角色
  4. 查看预览面板:
    • 应该显示真实的标签列表 (如果有标签)
    • 应该显示空状态 (如果没有标签)
    • 标签应该有真实的缩略图 (如果有上传)
    • 点击"生成"按钮应该提示"功能未实现"
    • 不应该显示"正视图、侧视图、背视图"

相关文件

已修改的文件

  • client/src/components/features/preview/hooks/usePreviewData.ts (核心修改: 移除"正视图、侧视图、背视图"生成逻辑)
  • client/src/components/features/preview/hooks/usePreviewActions.ts (移除假的AI生成逻辑)
  • client/src/components/features/preview/SoundEffectPreview.tsx (移除 mockStoryboardSoundEffects)
  • client/src/components/features/preview/ResourceInfoPanel.tsx (移除所有mock imports)

未修改的文件 (合理保留 mock)

  • client/src/components/features/preview/HistoryPanel.tsx (历史记录UI,纯展示)
  • client/src/components/features/preview/tabs/ResourceProfileTab.tsx (配音选择)
  • client/src/components/features/preview/dialogs/VoiceSelectionDialog.tsx (配音选择)

总结

本次清理彻底移除了资源预览核心功能中的所有 mock 数据,确保用户看到的都是真实的项目数据。

对于尚未实现的功能 (视频、音效、AI生成),采取了以下策略:

  • 视频/音效: 临时返回空数组,不影响其他功能,等待API实现
  • AI生成: 显示"功能未实现"提示,避免生成误导性的假数据

核心原则: 宁可显示空数据,也不显示假数据,确保用户对系统状态有正确的认知。