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.
 

88 KiB

Jointo(jointo)产品需求开发文档(完整版)

目标:用 React 前端完整还原 Figma Make 设计稿的所有 UI 元素、交互逻辑和功能细节。
文档版本:v2.0 - 完整详细版
项目域名https://www.jointo.ai


目录

  1. 产品概述
  2. 目标与范围
  3. 用户与使用场景
  4. 整体布局架构
  5. 详细功能需求
  6. UI/UX 交互细节
  7. 数据模型
  8. API 接口规范
  9. 技术方案
  10. 非功能需求
  11. 开发迭代计划

1. 产品概述

1.1 产品定位

Jointo是一个面向视频创作者、运营人员和营销团队的 AI 驱动视频制作平台。提供从分镜策划、素材管理、视频剪辑到音效/字幕/配音的一体化工作流程。

1.2 核心价值

  • 全流程覆盖:分镜 → 资源 → 视频 → 音效 → 字幕 → 配音 → 导出
  • AI 能力集成:大量使用 AI 生成和辅助功能,降低制作门槛
  • 协作支持:支持多人协同编辑和项目管理
  • 实时预览:所见即所得的预览体验

1.3 产品名称


2. 目标与范围

2.1 本期(MVP)目标

2.1.1 UI 还原

  • 完整还原所有页面布局和视觉元素
  • 还原所有按钮、图标、文本内容
  • 还原所有颜色、字体、间距、阴影等视觉样式
  • 还原所有交互状态(hover、active、disabled、selected)

2.1.2 功能实现

  • 所有前端交互逻辑(点击、切换、选择、输入)
  • 数据联动(项目切换、分镜选择、资源关联)
  • 状态管理(当前项目、选中分镜、时间轴位置等)
  • AI 功能入口(统一弹窗/抽屉,mock 数据返回)

2.1.3 交互体验

  • 流畅的页面切换和状态变化
  • 合理的加载状态和反馈提示
  • 新手引导流程
  • 响应式布局适配

2.2 不在本期范围

  • 真实的 AI 推理和生成(使用 mock 数据)
  • 真实的视频渲染和播放(使用占位图)
  • 真实的视频导出功能(占位按钮)
  • 完整的账号体系和权限系统(前端 mock)
  • 后端 API 对接(预留接口,使用 mock)

3. 用户与使用场景

3.1 用户角色

  1. 视频创作者/编辑

    • 使用分镜功能规划视频结构
    • 使用 AI 生成视频素材
    • 在时间轴上编排视频片段
    • 添加音效、字幕、配音
  2. 运营/营销人员

    • 快速制作广告片、宣传片
    • 使用 AI 工具提升制作效率
    • 管理多个项目
  3. 协作者

    • 查看和编辑协同项目
    • 参与项目讨论和备注

3.2 典型使用流程

  1. 创建/选择项目

    • 点击「新建项目」或从列表选择现有项目
    • 项目自动加载,显示分镜列表
  2. 编辑分镜

    • 查看/编辑分镜描述文案
    • 为每个分镜配置资源(人物、场景、道具)
    • 插入新分镜或删除分镜
  3. 生成和管理素材

    • 使用 AI 生成视频素材
    • 从素材库选择已有素材
    • 在时间轴上排列素材
  4. 完善视频

    • 添加音效、字幕、配音
    • 在预览窗口查看效果
    • 调整时间轴上的素材位置
  5. 导出项目

    • 点击「导出项目」(MVP 为占位功能)

4. 整体布局架构

4.1 页面结构(单页应用 SPA)

┌─────────────────────────────────────────────────────────────┐
│  应用顶部栏(TopBar)                                        │
│  Logo | 新建/导出/AI工具箱 | 权限/协作者/通知/备注/设置      │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────┬──────────────────────────────────┬──────────┐ │
│ │          │  中间区域(CenterArea)            │          │ │
│ │ 左侧栏   │ ┌──────┬──────────────┬────────┐ │  右侧栏  │ │
│ │          │ │分镜  │  预览窗口    │  AI   │ │          │ │
│ │ 项目/    │ │列表  │              │ 输入区 │ │ 资源/    │ │
│ │ 素材库   │ │      │  1920x1080   │        │ │ 视频/    │ │
│ │          │ │      │  主预览图    │        │ │ 音效/    │ │
│ │          │ │      │  预览1/2    │        │ │ 字幕/    │ │
│ │          │ │      │              │        │ │ 配音     │ │
│ │          │ │      │  播放控制    │        │ │          │ │
│ │          │ │      │  时间码      │        │ │          │ │
│ └──────────┴──────────────────────────────────┴──────────┘ │
├─────────────────────────────────────────────────────────────┤
│  时间轴(TimelinePanel)                                     │
│  时间轴 | 缩小 | 100% | 放大                                 │
│  0s───────────────────────────────────────────────60s       │
│  分镜/资源/视频/音效/字幕/配音轨道                           │
│  播放控制 | 时间码 | 缩放                                    │
│                                                             │
│ 新手引导浮层(OnboardingOverlay)                           │
│ Cookie 提示(Consent Manager)                              │
└─────────────────────────────────────────────────────────────┘

4.2 React 组件层级结构

App
├── Layout
│   ├── TopBar
│   │   ├── Logo
│   │   ├── ProjectActions (新建/导出/AI工具箱)
│   │   └── RightActions (权限/协作者/通知/备注/设置)
│   ├── MainContent
│   │   ├── LeftSidebar
│   │   │   ├── Tabs (项目/素材库)
│   │   │   ├── ProjectList
│   │   │   │   ├── MyProjects
│   │   │   │   └── CollabProjects
│   │   │   └── LibraryPanel
│   │   │       ├── SearchBox (搜索项目文件)
│   │   │       ├── LibraryTabs (角色/场景/道具/实拍)
│   │   │       └── LibraryContentList (内容列表)
│   │   ├── CenterArea
│   │   │   ├── StoryboardPanel (分镜列表)
│   │   │   │   ├── StoryboardHeader (分镜描述 | 调整按钮)
│   │   │   │   ├── StoryboardList
│   │   │   │   │   └── StoryboardItem (×6)
│   │   │   │   └── InsertStoryboardButton (×6)
│   │   │   ├── PreviewPanel (预览窗口)
│   │   │   │   ├── PreviewHeader (预览窗口 | 适应/填充)
│   │   │   │   ├── PreviewContent (内容预览)
│   │   │   │   │   ├── MainPreviewImage
│   │   │   │   │   └── ThumbnailImages (预览1/预览2)
│   │   │   │   ├── ResolutionDisplay (1920 x 1080)
│   │   │   │   ├── ZoomControls (缩小 | 100% | 放大)
│   │   │   │   └── StatusBar (未选择素材)
│   │   │   ├── PlaybackControls
│   │   │   │   ├── PrevFrameButton
│   │   │   │   ├── PlayButton
│   │   │   │   ├── NextFrameButton
│   │   │   │   └── TimecodeDisplay (00:00:00:00)
│   │   │   └── AIPromptPanel (AI 输入区)
│   │   │       ├── AITabs (图片提示词/角度变换/镜头调整)
│   │   │       ├── PromptExamples (示例文本)
│   │   │       ├── PromptInput (输入框)
│   │   │       ├── ActionButtons (对话改图/发送)
│   │   │       └── ModelSelector (当前模型: 智能选择)
│   │   └── RightSidebar
│   │       ├── ResourceTabs (资源/视频/音效/字幕/配音)
│   │       ├── ResourcePanel
│   │       │   ├── AIGenerateButton (AI生成资源素材)
│   │       │   └── StoryboardGroups (×6,每组包含人物/场景/道具/视频)
│   │       ├── VideoPanel
│   │       │   ├── AIGenerateButton (AI生成视频素材)
│   │       │   └── VideoList (所有视频项)
│   │       ├── SoundEffectPanel
│   │       │   ├── AIGenerateButton (AI生成音效素材)
│   │       │   └── SoundList (所有音效项)
│   │       ├── SubtitlePanel
│   │       │   ├── AIGenerateButton (AI生成字幕素材)
│   │       │   └── SubtitleList (所有字幕项)
│   │       └── VoiceoverPanel
│   │           ├── AIGenerateButton (AI生成配音素材)
│   │           └── VoiceoverList (所有配音项)
│   └── TimelinePanel (时间轴)
│       ├── TimelineHeader (时间轴 | 缩小 | 100% | 放大)
│       ├── TimeScale (0s-60s)
│       ├── TimelineTracks
│       │   ├── StoryboardTrack (分镜轨道)
│       │   ├── ResourceTrack (资源轨道)
│       │   ├── VideoTrack (视频轨道)
│       │   ├── SoundTrack (音效轨道)
│       │   ├── SubtitleTrack (字幕轨道)
│       │   └── VoiceoverTrack (配音轨道)
│       └── AddTrackButton (添加轨道)
└── OnboardingOverlay (新手引导浮层)
    ├── StepIndicator (步骤 1 / 4)
    ├── StepTitle (项目与素材管理)
    ├── StepDescription
    ├── StepJumpButtons (跳转到步骤 1/2/3/4)
    └── NavigationButtons (上一步/跳过引导/下一步)

5. 详细功能需求

5.1 应用顶部栏(TopBar)

5.3.1 左侧区域

Logo 和标题

  • Logo 图标:可点击的图标
  • 标题文本"Jointo"
  • 交互:点击 Logo 可返回项目列表或刷新当前项目(可选功能)

项目操作按钮组

  • 新建项目按钮

    • 图标 + 文本:"新建项目"
    • 点击行为:打开「新建项目」弹窗
      • 输入项目名称
      • 输入项目描述(可选)
      • 选择项目类型(我的项目/协同项目)
      • 确认后创建项目,自动选中新项目
    • 状态:正常状态,hover 有反馈
  • 导出项目按钮

    • 图标 + 文本:"导出项目"
    • 点击行为:MVP 阶段显示提示「导出功能开发中」或下载项目 JSON 数据
    • 后续:调用导出 API,生成视频文件
  • AI工具箱按钮

    • 图标 + 文本:"AI工具箱"
    • 点击行为:打开侧边抽屉或 Modal,展示所有 AI 功能入口
      • 图片提示词
      • 角度变换
      • 镜头调整
      • AI生成分镜素材
      • AI生成资源素材
      • AI生成视频素材
      • AI生成音效素材
      • AI生成字幕素材
      • AI生成配音素材

5.3.2 右侧区域

权限管理按钮

  • 图标按钮(无文本)
  • 点击行为:打开权限管理弹窗
    • 显示项目成员列表(mock 数据)
    • 显示成员角色(所有者、编辑者、查看者)
    • 添加成员功能(MVP 为占位)
    • 移除成员功能(MVP 为占位)

协作者头像组按钮

  • 显示多个用户头像
  • 内容:"ZS" "LS" "WW" "+1"
  • 点击行为:显示协作者详情弹窗
    • 显示所有协作者列表
    • 显示每个协作者的角色和权限
  • Hover 效果:显示协作者名称提示

通知按钮

  • 图标按钮(无文本)
  • 点击行为:打开通知列表
    • 显示未读通知数量(红点标识)
    • 通知列表(mock 数据)
    • 标记已读功能

项目备注按钮

  • 图标按钮(无文本)
  • 点击行为:打开项目备注面板
    • 显示/编辑项目备注(富文本或纯文本)
    • 保存备注功能
    • 显示备注历史(可选)

设置按钮

  • 图标按钮(无文本)
  • 点击行为:打开项目设置弹窗
    • 项目基本信息(名称、描述)
    • 视频设置(分辨率、帧率、时长)
    • 导出设置(格式、质量)
    • 其他设置选项

5.4 左侧栏(LeftSidebar)

5.4.1 Tab 切换

Tab 按钮组

  • 项目 Tab(默认选中)
  • 素材库 Tab
  • 样式:选中状态有视觉区分(下划线/背景色/文字颜色)
  • 交互:点击切换显示对应内容区域

5.4.2 项目列表(项目 Tab 下)

分组结构

  • 我的项目分组

    • 分组标题:"我的项目"
    • 分组图标:文件夹图标
    • 可折叠/展开(默认展开)
  • 协同项目分组

    • 分组标题:"协同项目"
    • 分组图标:协作图标
    • 可折叠/展开(默认展开)

项目卡片列表

每个项目卡片包含:

  • 缩略图:项目封面图(左侧)
  • 项目名称:文本显示
  • 更多操作按钮:hover 显示,点击显示菜单(编辑、删除、复制等)

示例项目(按设计稿):

  1. 西游记之大圣归来
  2. 琅琊榜
  3. 流浪地球
  4. 蒙牛新年好礼2025广告片
  5. 十三邀

交互行为

  • 点击项目卡片:切换当前项目
    • 更新中间区域的分镜列表
    • 更新右侧的资源/视频/音效/字幕/配音数据
    • 更新时间轴内容
    • 项目卡片显示选中状态(高亮/边框)
  • Hover 项目卡片:显示预览信息或操作按钮
  • 点击更多按钮:显示操作菜单(编辑、删除、复制、分享等)

5.4.3 素材库(素材库 Tab 下)

搜索功能

  • 搜索框:位于素材库顶部
    • 占位文本:"搜索项目文件..."
    • 支持输入项目名称进行搜索
    • 实时搜索,显示匹配的项目文件列表

Tab 分类

  • 搜索框下方显示 4 个 Tab 按钮:
    • 角色 Tab
    • 场景 Tab
    • 道具 Tab
    • 实拍 Tab
  • Tab 样式:选中状态有视觉区分(下划线/背景色/文字颜色)
  • Tab 互斥,只能选中一个

内容展示

  • 点击 Tab 后,显示对应类型的项目内容列表
  • 每个内容项显示:
    • 缩略图:素材预览图
    • 名称:素材名称
    • 来源项目:显示所属项目名称(可选)
  • 支持滚动浏览
  • 点击内容项:可添加到当前分镜(根据类型添加到对应资源分类)

交互行为

  • 搜索时:实时过滤项目文件
  • 切换 Tab:更新显示对应类型的内容
  • 点击内容项:添加到当前分镜的资源列表

5.5 中间区域 - 分镜列表(StoryboardPanel)

5.5.1 分镜描述区域头部

左侧标题

  • 图标 + 文本:"分镜描述"

右侧调整按钮

  • 图标 + 文本:"调整"
  • 点击行为:打开分镜调整面板
    • 批量编辑分镜
    • 调整分镜顺序
    • 分镜设置(时长、转场等)

5.5.2 分镜列表

分镜项结构(每个分镜包含):

  • 分镜缩略图:左侧显示
  • 分镜标题"分镜1" ~ "分镜6"(Heading 5 级别)
  • 更多按钮:右侧显示,点击显示菜单(编辑、删除、复制、插入等)
  • 分镜描述文本:段落文本,显示详细场景描述

分镜内容(按设计稿):

分镜1

  • 标题:"分镜1"
  • 描述:"清晨的阳光照进窗户,主人公在床上慢慢睁开眼睛,开始新的一天。窗外传来鸟鸣声,窗帘随着微风轻轻飘动。"

分镜2

  • 标题:"分镜2"
  • 描述:"主人公来到厨房,打开冰箱,拿出牛奶和面包,开始准备早餐。厨房里充满了温馨的气息,阳光从窗户洒进来。"

分镜3

  • 标题:"分镜3"
  • 描述:"坐在餐桌前,主人公一边享用早餐,一边浏览手机上的新闻。桌上摆放着精致的餐具和一杯热气腾腾的咖啡。"

分镜4

  • 标题:"分镜4"
  • 描述:"吃完早餐,主人公整理好餐具,将碗筷放进洗碗池,打开水龙头清洗。流水声和餐具碰撞的声音交织在一起。"

分镜5

  • 标题:"分镜5"
  • 描述:"回到房间,主人公打开衣柜,精心挑选今天要穿的衣服,换好衣服后对着镜子整理仪容。镜子里映出满意的笑容。"

分镜6

  • 标题:"分镜6"
  • 描述:"拿起背包和钥匙,主人公走向门口,回头看了一眼房间,打开门走出去,开始新一天的旅程。门在身后轻轻关上。"

5.5.3 插入新分镜按钮

位置

  • 在每个分镜项下方
  • 最后一个分镜项下方也有

样式

  • 图标 + 文本:"插入新分镜"
  • 按钮样式:次要按钮或链接样式

交互

  • 点击按钮:在当前分镜下方插入新分镜
    • 新分镜标题:"分镜X"(X 为下一个序号)
    • 新分镜描述:空文本,可编辑
    • 新分镜资源:空资源列表
    • 自动选中新插入的分镜

5.5.4 交互行为

分镜选择

  • 点击分镜项:选中该分镜
    • 分镜项显示选中状态(高亮/边框/背景色)
    • 预览窗口更新为当前分镜的预览图
    • 右侧资源面板高亮当前分镜的资源
    • 时间轴上高亮当前分镜的时间块

分镜编辑

  • 点击分镜标题:进入编辑模式(inline edit)

    • 标题变为可编辑输入框
    • 失去焦点或按 Enter 保存
    • 按 Esc 取消编辑
  • 点击分镜描述:进入编辑模式

    • 描述文本变为可编辑文本域
    • 支持多行编辑
    • 保存/取消按钮或自动保存

分镜删除

  • 点击更多按钮 → 删除:显示确认对话框
    • 确认后删除分镜
    • 更新分镜序号
    • 如果删除的是当前选中分镜,自动选中下一个分镜

分镜复制

  • 点击更多按钮 → 复制:复制当前分镜
    • 创建新分镜,内容与原分镜相同
    • 标题自动添加"(副本)"后缀
    • 插入到当前分镜下方

滚动行为

  • 分镜列表可垂直滚动
  • 选中分镜时,自动滚动到可视区域(如果不在视野内)

5.6 中间区域 - 预览窗口(PreviewPanel)

5.6.1 预览窗口头部

左侧标题

  • 图标 + 文本:"预览窗口"

右侧视图模式切换

  • 适应窗口按钮

    • 图标 + 文本:"适应窗口"
    • 选中状态:高亮显示
    • 点击行为:切换预览图适应窗口大小(保持宽高比)
  • 填充窗口按钮

    • 图标 + 文本:"填充窗口"
    • 选中状态:高亮显示
    • 点击行为:切换预览图填充整个窗口(可能裁剪)
  • 两个按钮互斥,只能选中一个

5.6.2 内容预览区域

主预览图

  • 显示当前选中分镜的主预览图
  • 尺寸标识:"1920 x 1080"(显示在预览图下方)
  • 支持点击放大查看(可选功能)

缩略图组

  • 预览1:小缩略图
  • 预览2:小缩略图
  • 点击缩略图:切换为主预览图
  • Hover 缩略图:显示预览信息

5.6.3 缩放控制

控制按钮组

  • 缩小按钮:图标按钮
  • 百分比显示"100%"(文本显示)
  • 放大按钮:图标按钮

交互行为

  • 点击缩小:缩放比例减小(如 100% → 75% → 50% → 25%)
  • 点击放大:缩放比例增大(如 25% → 50% → 75% → 100%)
  • 缩放范围:25% - 200%(可配置)
  • 缩放步进:25%(可配置)
  • 缩放影响:预览图大小和清晰度(前端 CSS transform)

5.6.4 状态栏

状态文本

  • 未选择素材时:"未选择素材"
  • 选择素材时:显示素材信息(名称、类型等)

5.7 中间区域 - 播放控制(PlaybackControls)

5.7.1 控制按钮

上一帧按钮

  • 图标按钮
  • 点击行为:播放位置向前移动一帧
  • 更新时间码显示

播放按钮

  • 图标按钮(播放/暂停图标切换)
  • 点击行为:
    • 当前为暂停状态:开始播放,图标变为暂停
    • 当前为播放状态:暂停播放,图标变为播放
  • MVP 阶段:仅更新状态,不真实播放视频

下一帧按钮

  • 图标按钮
  • 点击行为:播放位置向后移动一帧
  • 更新时间码显示

5.7.2 时间码显示

显示格式"00:00:00:00"

  • 格式:HH:MM:SS:FF(时:分:秒:帧)
  • 实时更新:播放时自动更新,手动操作时立即更新
  • 可编辑:点击时间码可手动输入(可选功能)

5.7.3 状态显示

缩放信息

  • 文本:"缩放: 100%"
  • 与预览窗口的缩放控制联动

素材状态

  • 文本:"未选择素材" 或显示当前选中素材信息

5.8 中间区域 - AI 输入区(AIPromptPanel)

5.8.1 AI 功能 Tab

Tab 按钮组

  • 图片提示词 Tab

    • 图标 + 文本:"图片提示词"
    • 选中状态:高亮显示
  • 角度变换 Tab

    • 图标 + 文本:"角度变换"
    • 选中状态:高亮显示
  • 镜头调整 Tab

    • 图标 + 文本:"镜头调整"
    • 选中状态:高亮显示
  • 三个 Tab 互斥,只能选中一个

  • 切换 Tab 时,输入框和示例文本相应更新

5.8.2 提示词示例区域

示例文本(图片提示词 Tab 下):

  • 第一段:"一位中年男性,穿着正装,站在办公室里"
  • 第二段:"背景是现代化的办公环境,玻璃窗外是城市景观"

显示方式

  • 灰色文本,作为提示示例
  • 可点击复制到输入框(可选功能)

5.8.3 输入框

占位文本"输入图片描述..."

当前示例内容(设计稿中):

  • "@孙悟空 拿着/金箍棒 在 #火焰山 跟@牛魔王 手持/芭蕉扇 互相攻击。"

输入框特性

  • 支持多行输入
  • 支持特殊语法:
    • @角色名:引用角色
    • /道具名:引用道具
    • #场景名:引用场景
  • 实时字数统计(可选)
  • 输入验证(可选)

5.8.4 操作按钮

对话改图按钮

  • 文本 + 图标:"对话改图"
  • 点击行为:
    • 调用 AI 对话改图 API(mock)
    • 显示加载状态
    • 返回结果(mock 数据)
    • 显示 Toast 提示

发送按钮

  • 图标按钮
  • 点击行为:
    • 验证输入内容
    • 调用 AI 生成 API(mock)
    • 显示加载状态
    • 返回结果并更新预览
    • 显示 Toast 提示

5.8.5 模型选择器

显示文本"当前模型: 智能选择"

交互

  • 点击打开下拉菜单
  • 显示可用模型列表:
    • 智能选择(默认)
    • 模型1
    • 模型2
    • ...
  • 选择模型后更新显示文本

5.9 时间轴(TimelinePanel)

5.9.1 时间轴头部

左侧标题

  • 图标 + 文本:"时间轴"

右侧缩放控制

  • 缩小按钮:图标按钮
  • 百分比显示"100%"(文本显示)
  • 放大按钮:图标按钮

交互行为

  • 点击缩小:时间轴刻度放大(显示更少时间范围,更精细)
  • 点击放大:时间轴刻度缩小(显示更多时间范围,更粗略)
  • 缩放范围:25% - 400%(可配置)
  • 缩放影响:时间刻度的显示密度和轨道块的宽度

5.9.2 时间刻度

刻度范围0s60s

显示方式

  • 每秒一个刻度标记
  • 每 5 秒一个主要刻度(更粗/更明显)
  • 每 10 秒显示时间标签(0s, 10s, 20s, ...)

滚动行为

  • 时间轴可水平滚动
  • 支持鼠标滚轮水平滚动
  • 支持拖拽滚动(可选)

5.9.3 轨道结构

分镜轨道

  • 轨道标题:"分镜"
  • 右侧按钮:"AI生成分镜素材"(图标 + 文本)
  • 轨道内容:显示 6 个分镜块
    • 每个分镜块显示:分镜名称(如"分镜1")+ 缩略图图标 + 删除按钮
    • 分镜块可点击选中
    • 分镜块可拖拽移动(MVP 可选实现)
    • 点击删除按钮:从时间轴移除该分镜块(不删除分镜本身)

资源轨道

  • 轨道标题:"资源"
  • 右侧按钮:"AI生成资源素材"(图标 + 文本)
  • 轨道内容:按分镜分组显示资源块
    • 每个分镜的资源块显示在对应时间位置
    • 资源块显示资源类型图标和名称

视频轨道

  • 轨道标题:"视频"
  • 右侧按钮:"AI生成视频素材"(图标 + 文本)
  • 轨道内容:显示所有视频片段
    • 每个视频块显示:视频名称 + 类型标签 + 删除按钮
    • 视频块显示时间范围(开始时间 - 结束时间)
    • 视频块可点击选中
    • 视频块可拖拽移动和调整长度(MVP 可选实现)
    • 点击删除按钮:从时间轴移除该视频块(不删除视频本身)

音效轨道

  • 轨道标题:"音效"
  • 右侧按钮:"AI生成音效素材"(图标 + 文本)
  • 轨道内容:显示所有音效片段
    • 每个音效块显示:音效名称 + 删除按钮
    • 音效块显示时间范围
    • 点击删除按钮:从时间轴移除该音效块(不删除音效本身)

字幕轨道

  • 轨道标题:"字幕"
  • 右侧按钮:"AI生成字幕素材"(图标 + 文本)
  • 轨道内容:显示所有字幕片段
    • 每个字幕块显示:字幕文本 + 删除按钮
    • 字幕块显示时间范围
    • 点击删除按钮:从时间轴移除该字幕块(不删除字幕本身)

配音轨道

  • 轨道标题:"配音"
  • 右侧按钮:"AI生成配音素材"(图标 + 文本)
  • 轨道内容:显示所有配音片段
    • 每个配音块显示:配音文本(如"旁白1:清晨醒来")+ 删除按钮
    • 配音块显示时间范围
    • 点击删除按钮:从时间轴移除该配音块(不删除配音本身)

5.9.4 添加轨道按钮

位置:时间轴底部

样式:图标 + 文本:"添加轨道"

交互

  • 点击打开「添加轨道」对话框
  • 选择轨道类型:
    • 资源
    • 视频
    • 音效
    • 字幕
    • 配音
  • 确认后添加新轨道到时间轴

5.9.6 时间轴状态显示

位置:时间轴底部,添加轨道按钮下方

状态文本

  • 未选择素材时:"未选择素材"
  • 选择素材时:显示选中素材信息(名称、类型、时间范围等)

5.9.5 时间轴交互

点击时间轴块

  • 选中对应素材/分镜
  • 更新预览窗口
  • 更新右侧面板选中状态
  • 播放位置跳转到块开始时间

拖拽时间轴块(MVP 可选):

  • 拖拽移动块的位置
  • 实时更新开始/结束时间
  • 显示时间提示

调整时间轴块长度(MVP 可选):

  • 拖拽块的两端调整长度
  • 实时更新结束时间
  • 显示时间提示

时间轴缩放

  • 使用缩放控制按钮调整显示范围
  • 使用鼠标滚轮缩放(Ctrl + 滚轮,可选)

5.10 右侧栏 - 资源面板(ResourcePanel)

5.10.1 面板头部

AI生成按钮

  • 图标 + 文本:"AI生成资源素材"
  • 点击行为:打开 AI 生成资源弹窗
    • 选择生成类型(人物/场景/道具/视频)
    • 输入描述
    • 选择分镜
    • 生成资源(mock)

5.10.2 分镜资源分组

分组结构:按分镜分组,共 6 组(分镜1-6)

每组包含子分类

人物分类

  • 分类标题:"人物"
  • 资源标签列表:
    • 每个资源显示为按钮标签
    • 标签右侧有 "×" 删除按钮
    • 示例(分镜1):"主角-睡姿"
  • 添加人物按钮
    • 图标 + 文本:"添加人物"
    • 点击行为:打开添加人物对话框
      • 从素材库选择
      • 或使用 AI 生成
      • 或上传图片

场景分类

  • 分类标题:"场景"
  • 资源标签列表:
    • 示例(分镜1):"卧室场景"
  • 添加场景按钮(如果有)

道具分类

  • 分类标题:"道具"
  • 资源标签列表:
    • 示例(分镜1):"床+窗帘"
  • 添加道具按钮
    • 图标 + 文本:"添加道具"
    • 点击行为:打开添加道具对话框

视频分类

  • 分类标题:"视频"
  • 添加视频按钮
    • 图标 + 文本:"添加视频"
    • 点击行为:打开添加视频对话框

5.10.3 资源数据(按设计稿)

分镜1 资源

  • 人物:"主角-睡姿"
  • 场景:"卧室场景"
  • 道具:"床+窗帘"

分镜2 资源

  • 人物:"主角-厨房"
  • 场景:"厨房场景"
  • 道具:"冰箱+食物"

分镜3 资源

  • 人物:"主角-用餐"
  • 场景:"餐桌场景"
  • 道具:"手机+餐具"

分镜4 资源

  • 人物:"主角-清洁"
  • 场景:"洗碗池场景"
  • 道具:"碗筷+水槽"

分镜5 资源

  • 人物:"主角-换装"
  • 场景:"卧室+衣柜"
  • 道具:"衣服+镜子"

分镜6 资源

  • 人物:"主角-出门"
  • 场景:"门口场景"
  • 道具:"背包+钥匙"

5.10.4 交互行为

资源标签交互

  • 点击资源标签:选中资源,更新预览
  • 点击 "×" 按钮:删除资源,显示确认提示(可选)

添加资源交互

  • 点击添加按钮:打开添加对话框
  • 选择/生成资源后:自动添加到当前分镜的资源列表

分镜切换联动

  • 切换选中分镜时:资源面板自动滚动到对应分镜的资源组
  • 高亮当前分镜的资源组

5.11 右侧栏 - 视频面板(VideoPanel)

5.11.1 面板头部

AI生成按钮

  • 图标 + 文本:"AI生成视频素材"
  • 点击行为:打开 AI 生成视频弹窗
    • 选择视频类型(图生视频/文生视频/首尾帧/融合生/实拍替换/实视频)
    • 输入描述或上传图片
    • 选择分镜
    • 生成视频(mock)

5.11.2 视频列表

视频项结构(每个视频包含):

  • 视频名称:文本显示
  • 类型标签:显示视频类型
    • "图生视频"
    • "文生视频"
    • "首尾帧视频"
    • "融合生视频"
    • "实拍替换"
    • "实视频"
  • 更多按钮:右侧显示,点击显示菜单(编辑、删除、复制等)

5.11.3 视频数据(按设计稿)

完整视频列表(共 24 个视频):

  1. 睁眼 - 图生视频
  2. 阳光 - 文生视频
  3. 起床 - 首尾帧视频
  4. 走廊 - 融合生视频
  5. 开冰箱 - 实拍替换
  6. 拿牛奶 - 图生视频
  7. 拿面包 - 文生视频
  8. 坐下 - 实视频
  9. 看手机 - 图生视频
  10. 收拾餐具 - 图生视频
  11. 走向洗碗池 - 文生视频
  12. 清洗 - 实拍替换
  13. 打开衣柜 - 图生视频
  14. 挑选衣服 - 融合生视频
  15. 换衣服 - 文生视频
  16. 照镜子 - 图生视频
  17. 整理发型 - 首尾帧视频
  18. 拿包 - 图生视频
  19. 回望 - 文生视频
  20. 开门离开 - 实拍替换

5.11.4 交互行为

视频选择

  • 点击视频项:选中视频
    • 视频项显示选中状态
    • 更新预览窗口
    • 时间轴上高亮对应视频块
    • 播放位置跳转到视频开始时间

视频编辑

  • 点击更多按钮 → 编辑:打开视频编辑对话框
    • 修改视频名称
    • 修改视频类型
    • 调整视频参数(MVP 为占位)

视频删除

  • 点击更多按钮 → 删除:显示确认对话框
    • 确认后删除视频
    • 从时间轴上移除对应视频块

5.12 右侧栏 - 音效面板(SoundEffectPanel)

5.12.1 面板头部

AI生成按钮

  • 图标 + 文本:"AI生成音效素材"
  • 点击行为:打开 AI 生成音效弹窗
    • 输入音效描述
    • 选择音效类型
    • 生成音效(mock)

5.12.2 音效列表

音效项结构(每个音效包含):

  • 音效名称:文本显示
  • 更多按钮:右侧显示,点击显示菜单

5.12.3 音效数据(按设计稿)

完整音效列表(共 16 个音效):

  1. 鸟叫
  2. 床铺声
  3. 脚步声
  4. 开门
  5. 拿东西
  6. 背景音
  7. 碗筷碰撞
  8. 水声
  9. 洗碗声
  10. 柜门
  11. 衣物摩擦
  12. 拉链
  13. 环境音
  14. 拉链(重复,可能是不同场景)
  15. 脚步声(重复)
  16. 开关门

5.12.4 交互行为

音效选择

  • 点击音效项:选中音效
    • 音效项显示选中状态
    • 时间轴上高亮对应音效块
    • 播放音效预览(MVP 为占位)

音效编辑/删除

  • 点击更多按钮:显示操作菜单
    • 编辑:修改音效名称
    • 删除:删除音效

5.13 右侧栏 - 字幕面板(SubtitlePanel)

5.13.1 面板头部

AI生成按钮

  • 图标 + 文本:"AI生成字幕素材"
  • 点击行为:打开 AI 生成字幕弹窗
    • 输入字幕文本
    • 选择时间位置
    • 生成字幕(mock)

5.13.2 字幕列表

字幕项结构(每个字幕包含):

  • 字幕文本:文本显示
  • 更多按钮:右侧显示,点击显示菜单

5.13.3 字幕数据(按设计稿)

完整字幕列表(共 16 个字幕):

  1. 早安
  2. 新的一天
  3. 去厨房
  4. 准备早餐
  5. 牛奶面包
  6. 享用
  7. 看新闻
  8. 收拾
  9. 清洗餐具
  10. 保持整洁
  11. 选衣服
  12. 今天穿什么
  13. 换装完成
  14. 完美
  15. 准备出门
  16. 新的旅程

5.13.4 交互行为

字幕选择

  • 点击字幕项:选中字幕
    • 字幕项显示选中状态
    • 时间轴上高亮对应字幕块
    • 预览窗口显示字幕(可选)

字幕编辑/删除

  • 点击更多按钮:显示操作菜单
    • 编辑:修改字幕文本和时间
    • 删除:删除字幕

5.14 右侧栏 - 配音面板(VoiceoverPanel)

5.14.1 面板头部

AI生成按钮

  • 图标 + 文本:"AI生成配音素材"
  • 点击行为:打开 AI 生成配音弹窗
    • 输入配音文本
    • 选择语音类型
    • 选择时间位置
    • 生成配音(mock)

5.14.2 配音列表

配音项结构(每个配音包含):

  • 配音文本:文本显示(如"旁白1:清晨醒来")
  • 更多按钮:右侧显示,点击显示菜单

5.14.3 配音数据(按设计稿)

完整配音列表(共 8 个配音):

  1. 旁白1:清晨醒来
  2. 旁白2:去厨房
  3. 旁白3:准备食物
  4. 旁白4:享用早餐
  5. 旁白5:收拾餐具
  6. 旁白6:选择穿搭
  7. 旁白7:整理仪容
  8. 旁白8:出发

5.14.4 交互行为

配音选择

  • 点击配音项:选中配音
    • 配音项显示选中状态
    • 时间轴上高亮对应配音块
    • 播放配音预览(MVP 为占位)

配音编辑/删除

  • 点击更多按钮:显示操作菜单
    • 编辑:修改配音文本和时间
    • 删除:删除配音

5.15 右侧栏 - Tab 切换

5.15.1 Tab 按钮组

Tab 列表

  • 资源 Tab
  • 视频 Tab
  • 音效 Tab
  • 字幕 Tab
  • 配音 Tab

5.15.2 交互行为

Tab 切换

  • 点击 Tab:切换显示对应面板
  • 选中 Tab 有视觉区分(下划线/背景色/文字颜色)
  • 切换时保持滚动位置(可选)

Tab 状态联动

  • 切换 Tab 时,时间轴上对应轨道自动滚动到可视区域(可选)

5.16 新手引导浮层(OnboardingOverlay)

5.16.1 浮层结构

跳过按钮

  • 位置:浮层右上角
  • 样式:图标按钮
  • 点击行为:关闭引导,写入 localStorage,不再显示

步骤指示器

  • 图标 + 文本:"步骤 1 / 4"
  • 显示当前步骤和总步骤数

步骤标题

  • Heading 3 级别:"项目与素材管理"

步骤描述

  • 段落文本:"在这里您可以新增、查看和管理项目,同时可以查看和管理项目中的所有素材资源。"

步骤跳转按钮组

  • 跳转到步骤 1 按钮
  • 跳转到步骤 2 按钮
  • 跳转到步骤 3 按钮
  • 跳转到步骤 4 按钮
  • 点击按钮:跳转到对应步骤,更新内容

导航按钮组

  • 上一步按钮
    • 图标 + 文本:"上一步"
    • 第一步时:disabled 状态
    • 点击行为:返回上一步
  • 跳过引导按钮
    • 文本:"跳过引导"
    • 点击行为:关闭引导,写入 localStorage
  • 下一步按钮
    • 文本 + 图标:"下一步"
    • 最后一步时:显示"完成"或隐藏
    • 点击行为:进入下一步

5.16.2 引导步骤内容(需要补充)

步骤 1:项目与素材管理

  • 描述:"在这里您可以新增、查看和管理项目,同时可以查看和管理项目中的所有素材资源。"
  • 高亮区域:左侧项目列表和素材库

步骤 2:分镜编辑(需要补充内容)

  • 描述:待补充
  • 高亮区域:分镜列表

步骤 3:预览和时间轴(需要补充内容)

  • 描述:待补充
  • 高亮区域:预览窗口和时间轴

步骤 4:AI 功能(需要补充内容)

  • 描述:待补充
  • 高亮区域:AI 输入区和 AI 生成按钮

5.16.3 交互行为

引导显示逻辑

  • 首次访问时自动显示
  • 检查 localStorage,如果已跳过则不显示
  • 可手动重新打开引导(设置中,可选功能)

步骤切换

  • 点击"下一步":进入下一步,更新内容和高亮区域
  • 点击"上一步":返回上一步
  • 点击步骤跳转按钮:直接跳转到指定步骤

引导关闭

  • 点击"跳过引导":关闭引导,写入 localStorage
  • 点击右上角关闭按钮:关闭引导,写入 localStorage
  • 完成所有步骤:自动关闭引导,写入 localStorage

5.17.1 提示内容

文本内容

  • 主文本:"This website uses cookies, pixel tags, and local storage for performance, personalization, and marketing purposes. Our use of some cookies may be considered a sale, sharing for behavioral advertising, or targeted advertising. For more, see our"
  • 隐私政策链接"privacy policy"https://www.figma.com/privacy/
  • 中间文本:". California Residents can learn how personal information is"
  • 收集链接"collected"https://www.figma.com/privacy/#ca-notice
  • 中间文本:", including how it is"
  • 使用链接"used"https://www.figma.com/privacy/#purpose
  • 中间文本:", whether it is"
  • 销售/共享链接""sold" or "shared""https://www.figma.com/privacy/#ca-notice
  • 中间文本:", and how long it is"
  • 保留链接"retained"https://www.figma.com/privacy/#retention
  • 结尾文本:"."

5.17.2 操作按钮

Opt out 按钮

  • 文本:"Opt out"
  • 点击行为:选择退出 Cookie,写入 localStorage

关闭按钮

  • 图标按钮
  • 点击行为:关闭提示,写入 localStorage(同意使用 Cookie)

5.17.3 交互行为

提示显示逻辑

  • 首次访问时显示
  • 检查 localStorage,如果已选择则不显示
  • 可手动重新打开(设置中,可选功能)

链接跳转

  • 所有链接在新标签页打开

6. UI/UX 交互细节

6.1 视觉样式规范

6.1.1 颜色系统

  • 主色调:根据 Figma 设计稿提取
  • 辅助色:警告色、成功色、错误色
  • 中性色:文本色、背景色、边框色
  • 状态色:hover、active、selected、disabled

6.1.2 字体系统

  • 字体家族:根据设计稿(可能包含中文字体)
  • 字体大小:标题、正文、辅助文本
  • 字重:正常、中等、粗体
  • 行高:根据设计稿

6.1.3 间距系统

  • 基础间距单位:4px 或 8px
  • 组件间距:根据设计稿提取
  • 内边距:按钮、输入框、卡片等
  • 外边距:组件之间的间距

6.1.4 圆角系统

  • 小圆角:按钮、标签
  • 中圆角:卡片、面板
  • 大圆角:弹窗、抽屉

6.1.5 阴影系统

  • 小阴影:卡片、按钮 hover
  • 中阴影:弹窗、抽屉
  • 大阴影:模态框

6.2 交互状态

6.2.1 按钮状态

  • 默认状态:正常显示
  • Hover 状态:鼠标悬停,视觉反馈(颜色变化、阴影、缩放)
  • Active 状态:点击时,视觉反馈
  • Disabled 状态:禁用,灰色,不可点击
  • Loading 状态:加载中,显示加载动画

6.2.2 输入框状态

  • 默认状态:正常显示
  • Focus 状态:获得焦点,边框高亮
  • Error 状态:错误,红色边框和提示
  • Disabled 状态:禁用,灰色

6.2.3 选中状态

  • 分镜选中:高亮背景、边框、或左侧指示条
  • 资源选中:高亮背景或边框
  • Tab 选中:下划线、背景色、或文字颜色变化

6.3 动画与过渡

6.3.1 页面切换

  • 淡入淡出:页面切换时
  • 滑动:侧边栏展开/收起
  • 缩放:弹窗打开/关闭

6.3.2 状态变化

  • 颜色过渡:hover、active 状态变化
  • 位置过渡:拖拽、滚动
  • 尺寸过渡:展开/收起

6.3.3 加载动画

  • 按钮加载:旋转图标或进度条
  • 内容加载:骨架屏或加载指示器
  • AI 生成:进度条或动画效果

6.4 响应式设计

6.4.1 断点设置

  • 桌面:> 1200px(默认布局)
  • 平板:768px - 1200px(调整布局)
  • 移动端:< 768px(简化布局,可选实现)

6.4.2 布局适配

  • 侧边栏:可收起/展开
  • 面板:可调整宽度(可选)
  • 时间轴:可全屏显示(可选)

6.5 可访问性(Accessibility)

6.5.1 键盘导航

  • Tab 键:在可交互元素间切换
  • Enter/Space:激活按钮
  • Esc:关闭弹窗/取消操作
  • 方向键:在列表项间导航

6.5.2 屏幕阅读器

  • ARIA 标签:为交互元素添加标签
  • 语义化 HTML:使用正确的 HTML 标签
  • 焦点管理:弹窗打开时聚焦到第一个元素

6.5.3 视觉辅助

  • 焦点指示器:清晰的焦点样式
  • 对比度:文本与背景的对比度符合 WCAG 标准
  • 字体大小:支持浏览器缩放

7. 数据模型

7.1 核心数据类型

// 项目类型
type Project = {
  id: string;
  name: string;
  description?: string;
  thumbnailUrl?: string;
  type: "mine" | "collab";
  createdAt: number;
  updatedAt: number;
  storyboards: Storyboard[];
  settings: ProjectSettings;
};

// 项目设置
type ProjectSettings = {
  resolution: {
    width: number;
    height: number;
  };
  frameRate: number;
  duration: number; // 秒
  exportFormat?: string;
  exportQuality?: string;
};

// 分镜类型
type Storyboard = {
  id: string;
  title: string; // "分镜1", "分镜2", ...
  description: string;
  thumbnailUrl?: string;
  resources: StoryboardResources;
  startTime: number; // 在时间轴上的开始时间(秒)
  endTime: number; // 在时间轴上的结束时间(秒)
  order: number; // 分镜顺序
};

// 分镜资源
type StoryboardResources = {
  characters: ResourceItem[]; // 人物
  scenes: ResourceItem[]; // 场景
  props: ResourceItem[]; // 道具
  videos: string[]; // 视频 ID 列表
};

// 资源项
type ResourceItem = {
  id: string;
  name: string;
  type: "character" | "scene" | "prop";
  thumbnailUrl?: string;
  assetUrl?: string;
};

// 视频资产
type VideoAsset = {
  id: string;
  name: string;
  type: "img2video" | "text2video" | "keyframe" | "fusion" | "replace" | "real";
  thumbnailUrl?: string;
  videoUrl?: string;
  startTime: number; // 在时间轴上的开始时间(秒)
  endTime: number; // 在时间轴上的结束时间(秒)
  storyboardId?: string; // 关联的分镜 ID
};

// 音效资产
type SoundEffect = {
  id: string;
  name: string;
  audioUrl?: string;
  startTime: number;
  endTime: number;
  volume?: number; // 0-100
};

// 字幕资产
type Subtitle = {
  id: string;
  text: string;
  startTime: number;
  endTime: number;
  style?: SubtitleStyle;
};

type SubtitleStyle = {
  fontSize?: number;
  color?: string;
  position?: "top" | "center" | "bottom";
  backgroundColor?: string;
};

// 配音资产
type Voiceover = {
  id: string;
  text: string;
  audioUrl?: string;
  startTime: number;
  endTime: number;
  voiceType?: string; // 语音类型
  volume?: number;
};

// 时间轴轨道
type TimelineTrack = {
  id: string;
  type: "storyboard" | "resource" | "video" | "sound" | "subtitle" | "voice";
  name: string;
  items: TimelineItem[];
  visible: boolean;
  locked: boolean;
};

// 时间轴项
type TimelineItem = {
  id: string;
  refId: string; // 指向 storyboard / video / sound / subtitle / voiceover 的 ID
  type: "storyboard" | "video" | "sound" | "subtitle" | "voice";
  start: number; // 开始时间(秒)
  end: number; // 结束时间(秒)
  trackId: string; // 所属轨道 ID
};

// AI 生成请求
type AIGenerateRequest = {
  type: "image" | "video" | "sound" | "subtitle" | "voice" | "resource";
  prompt: string;
  model?: string;
  parameters?: Record<string, any>;
  storyboardId?: string;
};

// AI 生成响应
type AIGenerateResponse = {
  success: boolean;
  data?: any;
  error?: string;
  jobId?: string; // 异步任务 ID
};

7.2 状态管理数据结构

// 应用全局状态
type AppState = {
  // 当前项目
  currentProject: Project | null;

  // 当前选中的分镜
  selectedStoryboard: Storyboard | null;

  // 当前选中的资源/视频/音效/字幕/配音
  selectedItem: {
    type: "resource" | "video" | "sound" | "subtitle" | "voice" | null;
    id: string | null;
  };

  // 预览窗口状态
  preview: {
    mode: "fit" | "fill"; // 适应窗口 / 填充窗口
    zoom: number; // 缩放比例,如 100 表示 100%
    currentImageUrl?: string;
  };

  // 播放控制状态
  playback: {
    isPlaying: boolean;
    currentTime: number; // 当前播放时间(秒)
    timecode: string; // 时间码 "00:00:00:00"
  };

  // 时间轴状态
  timeline: {
    zoom: number; // 时间轴缩放比例
    scrollPosition: number; // 滚动位置
    selectedTrackId: string | null;
  };

  // 右侧面板状态
  rightPanel: {
    activeTab: "resource" | "video" | "sound" | "subtitle" | "voice";
    scrollPosition: number;
  };

  // AI 输入区状态
  aiPrompt: {
    activeTab: "image" | "angle" | "lens";
    inputText: string;
    selectedModel: string;
  };

  // 新手引导状态
  onboarding: {
    isVisible: boolean;
    currentStep: number;
    totalSteps: number;
    skipped: boolean; // 是否已跳过
  };

  // UI 状态
  ui: {
    isLeftSidebarCollapsed: boolean;
    isRightSidebarCollapsed: boolean;
    modals: {
      [key: string]: boolean; // 各种弹窗的显示状态
    };
  };
};

7.3 Mock 数据示例

// Mock 项目数据
const mockProjects: Project[] = [
  {
    id: "proj-1",
    name: "西游记之大圣归来",
    type: "mine",
    thumbnailUrl: "/thumbnails/proj-1.jpg",
    createdAt: Date.now() - 86400000 * 7,
    updatedAt: Date.now() - 86400000,
    storyboards: mockStoryboards,
    settings: {
      resolution: { width: 1920, height: 1080 },
      frameRate: 30,
      duration: 60,
    },
  },
  {
    id: "proj-2",
    name: "琅琊榜",
    type: "mine",
    thumbnailUrl: "/thumbnails/proj-2.jpg",
    createdAt: Date.now() - 86400000 * 14,
    updatedAt: Date.now() - 86400000 * 2,
    storyboards: [],
    settings: {
      resolution: { width: 1920, height: 1080 },
      frameRate: 30,
      duration: 60,
    },
  },
  // ... 更多项目
];

// Mock 分镜数据
const mockStoryboards: Storyboard[] = [
  {
    id: "sb-1",
    title: "分镜1",
    description:
      "清晨的阳光照进窗户,主人公在床上慢慢睁开眼睛,开始新的一天。窗外传来鸟鸣声,窗帘随着微风轻轻飘动。",
    order: 1,
    startTime: 0,
    endTime: 10,
    resources: {
      characters: [{ id: "char-1", name: "主角-睡姿", type: "character" }],
      scenes: [{ id: "scene-1", name: "卧室场景", type: "scene" }],
      props: [{ id: "prop-1", name: "床+窗帘", type: "prop" }],
      videos: ["video-1", "video-2", "video-3", "video-4"],
    },
  },
  // ... 更多分镜
];

// Mock 视频数据
const mockVideos: VideoAsset[] = [
  {
    id: "video-1",
    name: "睁眼",
    type: "img2video",
    startTime: 0,
    endTime: 2,
    storyboardId: "sb-1",
  },
  {
    id: "video-2",
    name: "阳光",
    type: "text2video",
    startTime: 2,
    endTime: 4,
    storyboardId: "sb-1",
  },
  // ... 更多视频
];

8. API 接口规范

8.1 API 设计原则

8.1.1 基础规范

  • 协议:HTTPS
  • 数据格式:JSON
  • 请求方法:RESTful(GET、POST、PUT、DELETE、PATCH)
  • 认证方式:Bearer Token(JWT)
  • 响应格式:统一响应结构

8.1.2 统一响应结构

// 成功响应
type ApiSuccessResponse<T> = {
  success: true;
  data: T;
  message?: string;
};

// 错误响应
type ApiErrorResponse = {
  success: false;
  error: {
    code: string;
    message: string;
    details?: any;
  };
};

// 分页响应
type ApiPaginatedResponse<T> = {
  success: true;
  data: T[];
  pagination: {
    page: number;
    pageSize: number;
    total: number;
    totalPages: number;
  };
};

8.1.3 错误码规范

enum ApiErrorCode {
  // 通用错误
  UNAUTHORIZED = "UNAUTHORIZED", // 401 未授权
  FORBIDDEN = "FORBIDDEN", // 403 禁止访问
  NOT_FOUND = "NOT_FOUND", // 404 资源不存在
  VALIDATION_ERROR = "VALIDATION_ERROR", // 400 参数验证失败
  INTERNAL_ERROR = "INTERNAL_ERROR", // 500 服务器错误

  // 业务错误
  PROJECT_NOT_FOUND = "PROJECT_NOT_FOUND",
  STORYBOARD_NOT_FOUND = "STORYBOARD_NOT_FOUND",
  AI_GENERATION_FAILED = "AI_GENERATION_FAILED",
  AI_GENERATION_TIMEOUT = "AI_GENERATION_TIMEOUT",
  EXPORT_FAILED = "EXPORT_FAILED",
}

8.2 Mock 数据与真实 API 区分

8.2.1 前端纯状态管理(无需 API)

以下功能仅在前端状态管理,无需调用后端 API:

  • UI 状态:Tab 切换、面板展开/收起、弹窗显示/隐藏
  • 选中状态:分镜选中、资源选中、时间轴选中
  • 预览窗口状态:缩放比例、视图模式(适应/填充)
  • 时间轴状态:时间轴缩放、滚动位置
  • 播放控制状态:播放/暂停、当前时间(前端模拟)
  • 新手引导状态:当前步骤、是否跳过(localStorage)

8.2.2 需要 Mock 数据的 API(MVP 阶段)

以下功能在 MVP 阶段使用 Mock 数据,但需要按照真实 API 格式实现:

  • 🔶 项目 CRUD:创建、读取、更新、删除项目
  • 🔶 分镜 CRUD:创建、读取、更新、删除分镜
  • 🔶 资源管理:添加、删除资源(人物、场景、道具)
  • 🔶 视频管理:添加、删除、更新视频
  • 🔶 音效管理:添加、删除、更新音效
  • 🔶 字幕管理:添加、删除、更新字幕
  • 🔶 配音管理:添加、删除、更新配音
  • 🔶 时间轴操作:保存时间轴配置
  • 🔶 AI 生成功能:所有 AI 生成请求
  • 🔶 项目导出:导出项目配置或视频

8.2.3 真实后端 API(后续对接)

所有标记为 🔶 的功能,在后续阶段需要对接真实后端 API。

8.3 API 接口详细定义

8.3.1 项目管理 API

8.3.1.1 获取项目列表
// 请求
GET /api/v1/projects
Query Parameters:
  - type?: 'mine' | 'collab'  // 项目类型,不传则返回全部
  - page?: number            // 页码,默认 1
  - pageSize?: number        // 每页数量,默认 20

// 响应
type GetProjectsResponse = ApiPaginatedResponse<Project>;

// Mock 实现
// 返回本地 Mock 数据,格式与真实 API 一致
8.3.1.2 获取项目详情
// 请求
GET /api/v1/projects/:projectId

// 响应
type GetProjectResponse = ApiSuccessResponse<Project>;

// Mock 实现
// 从 Mock 数据中查找对应项目
8.3.1.3 创建项目
// 请求
POST /api/v1/projects
Body: {
  name: string;
  description?: string;
  type: 'mine' | 'collab';
  settings?: {
    resolution: { width: number; height: number };
    frameRate: number;
    duration: number;
  };
}

// 响应
type CreateProjectResponse = ApiSuccessResponse<Project>;

// Mock 实现
// 生成新项目 ID,添加到 Mock 数据列表
8.3.1.4 更新项目
// 请求
PUT /api/v1/projects/:projectId
Body: {
  name?: string;
  description?: string;
  settings?: ProjectSettings;
}

// 响应
type UpdateProjectResponse = ApiSuccessResponse<Project>;

// Mock 实现
// 更新 Mock 数据中对应项目
8.3.1.5 删除项目
// 请求
DELETE /api/v1/projects/:projectId

// 响应
type DeleteProjectResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除对应项目
8.3.1.6 导出项目
// 请求
POST /api/v1/projects/:projectId/export
Body: {
  format: 'json' | 'mp4' | 'mov';  // 导出格式
  quality?: 'low' | 'medium' | 'high';
  resolution?: { width: number; height: number };
}

// 响应(同步)
type ExportProjectResponse = ApiSuccessResponse<{
  downloadUrl: string;  // 下载链接
  expiresAt: number;    // 过期时间戳
}>;

// 响应(异步)
type ExportProjectAsyncResponse = ApiSuccessResponse<{
  jobId: string;        // 任务 ID
  status: 'pending' | 'processing' | 'completed' | 'failed';
}>;

// Mock 实现
// 返回模拟的下载链接或任务 ID

8.3.2 分镜管理 API

8.3.2.1 获取项目分镜列表
// 请求
GET /api/v1/projects/:projectId/storyboards

// 响应
type GetStoryboardsResponse = ApiSuccessResponse<Storyboard[]>;

// Mock 实现
// 返回项目下的所有分镜
8.3.2.2 获取分镜详情
// 请求
GET /api/v1/storyboards/:storyboardId

// 响应
type GetStoryboardResponse = ApiSuccessResponse<Storyboard>;

// Mock 实现
// 从 Mock 数据中查找对应分镜
8.3.2.3 创建分镜
// 请求
POST /api/v1/projects/:projectId/storyboards
Body: {
  title: string;
  description?: string;
  order?: number;  // 插入位置,不传则追加到最后
}

// 响应
type CreateStoryboardResponse = ApiSuccessResponse<Storyboard>;

// Mock 实现
// 生成新分镜 ID,插入到指定位置
8.3.2.4 更新分镜
// 请求
PUT /api/v1/storyboards/:storyboardId
Body: {
  title?: string;
  description?: string;
  startTime?: number;
  endTime?: number;
  order?: number;
}

// 响应
type UpdateStoryboardResponse = ApiSuccessResponse<Storyboard>;

// Mock 实现
// 更新 Mock 数据中对应分镜
8.3.2.5 删除分镜
// 请求
DELETE /api/v1/storyboards/:storyboardId

// 响应
type DeleteStoryboardResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除对应分镜
8.3.2.6 更新分镜资源
// 请求
PUT /api/v1/storyboards/:storyboardId/resources
Body: {
  characters?: ResourceItem[];
  scenes?: ResourceItem[];
  props?: ResourceItem[];
  videos?: string[];  // 视频 ID 列表
}

// 响应
type UpdateStoryboardResourcesResponse = ApiSuccessResponse<StoryboardResources>;

// Mock 实现
// 更新分镜的资源列表

8.3.3 资源管理 API

8.3.3.1 获取资源列表
// 请求
GET /api/v1/resources
Query Parameters:
  - type?: 'character' | 'scene' | 'prop';
  - storyboardId?: string;
  - page?: number;
  - pageSize?: number;

// 响应
type GetResourcesResponse = ApiPaginatedResponse<ResourceItem>;

// Mock 实现
// 返回资源列表,支持筛选
8.3.3.2 上传资源
// 请求
POST /api/v1/resources
Content-Type: multipart/form-data
Body: {
  file: File;
  name: string;
  type: 'character' | 'scene' | 'prop';
  storyboardId?: string;
}

// 响应
type UploadResourceResponse = ApiSuccessResponse<ResourceItem>;

// Mock 实现
// 生成资源 ID 和 URL,保存到 Mock 数据
8.3.3.3 删除资源
// 请求
DELETE /api/v1/resources/:resourceId

// 响应
type DeleteResourceResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除资源

8.3.4 视频管理 API

8.3.4.1 获取视频列表
// 请求
GET /api/v1/videos
Query Parameters:
  - projectId?: string;
  - storyboardId?: string;
  - page?: number;
  - pageSize?: number;

// 响应
type GetVideosResponse = ApiPaginatedResponse<VideoAsset>;

// Mock 实现
// 返回视频列表
8.3.4.2 创建视频
// 请求
POST /api/v1/videos
Body: {
  name: string;
  type: 'img2video' | 'text2video' | 'keyframe' | 'fusion' | 'replace' | 'real';
  storyboardId?: string;
  startTime?: number;
  endTime?: number;
}

// 响应
type CreateVideoResponse = ApiSuccessResponse<VideoAsset>;

// Mock 实现
// 生成视频 ID,添加到 Mock 数据
8.3.4.3 更新视频
// 请求
PUT /api/v1/videos/:videoId
Body: {
  name?: string;
  startTime?: number;
  endTime?: number;
  thumbnailUrl?: string;
}

// 响应
type UpdateVideoResponse = ApiSuccessResponse<VideoAsset>;

// Mock 实现
// 更新视频信息
8.3.4.4 删除视频
// 请求
DELETE /api/v1/videos/:videoId

// 响应
type DeleteVideoResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除视频

8.3.5 音效管理 API

8.3.5.1 获取音效列表
// 请求
GET /api/v1/sound-effects
Query Parameters:
  - projectId?: string;
  - page?: number;
  - pageSize?: number;

// 响应
type GetSoundEffectsResponse = ApiPaginatedResponse<SoundEffect>;

// Mock 实现
// 返回音效列表
8.3.5.2 创建音效
// 请求
POST /api/v1/sound-effects
Body: {
  name: string;
  startTime: number;
  endTime: number;
  volume?: number;
  audioUrl?: string;  // 如果上传文件
}

// 响应
type CreateSoundEffectResponse = ApiSuccessResponse<SoundEffect>;

// Mock 实现
// 生成音效 ID,添加到 Mock 数据
8.3.5.3 更新音效
// 请求
PUT /api/v1/sound-effects/:soundEffectId
Body: {
  name?: string;
  startTime?: number;
  endTime?: number;
  volume?: number;
}

// 响应
type UpdateSoundEffectResponse = ApiSuccessResponse<SoundEffect>;

// Mock 实现
// 更新音效信息
8.3.5.4 删除音效
// 请求
DELETE /api/v1/sound-effects/:soundEffectId

// 响应
type DeleteSoundEffectResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除音效

8.3.6 字幕管理 API

8.3.6.1 获取字幕列表
// 请求
GET /api/v1/subtitles
Query Parameters:
  - projectId?: string;
  - page?: number;
  - pageSize?: number;

// 响应
type GetSubtitlesResponse = ApiPaginatedResponse<Subtitle>;

// Mock 实现
// 返回字幕列表
8.3.6.2 创建字幕
// 请求
POST /api/v1/subtitles
Body: {
  text: string;
  startTime: number;
  endTime: number;
  style?: SubtitleStyle;
}

// 响应
type CreateSubtitleResponse = ApiSuccessResponse<Subtitle>;

// Mock 实现
// 生成字幕 ID,添加到 Mock 数据
8.3.6.3 更新字幕
// 请求
PUT /api/v1/subtitles/:subtitleId
Body: {
  text?: string;
  startTime?: number;
  endTime?: number;
  style?: SubtitleStyle;
}

// 响应
type UpdateSubtitleResponse = ApiSuccessResponse<Subtitle>;

// Mock 实现
// 更新字幕信息
8.3.6.4 删除字幕
// 请求
DELETE /api/v1/subtitles/:subtitleId

// 响应
type DeleteSubtitleResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除字幕

8.3.7 配音管理 API

8.3.7.1 获取配音列表
// 请求
GET /api/v1/voiceovers
Query Parameters:
  - projectId?: string;
  - page?: number;
  - pageSize?: number;

// 响应
type GetVoiceoversResponse = ApiPaginatedResponse<Voiceover>;

// Mock 实现
// 返回配音列表
8.3.7.2 创建配音
// 请求
POST /api/v1/voiceovers
Body: {
  text: string;
  startTime: number;
  endTime: number;
  voiceType?: string;
  volume?: number;
}

// 响应
type CreateVoiceoverResponse = ApiSuccessResponse<Voiceover>;

// Mock 实现
// 生成配音 ID,添加到 Mock 数据
8.3.7.3 更新配音
// 请求
PUT /api/v1/voiceovers/:voiceoverId
Body: {
  text?: string;
  startTime?: number;
  endTime?: number;
  voiceType?: string;
  volume?: number;
}

// 响应
type UpdateVoiceoverResponse = ApiSuccessResponse<Voiceover>;

// Mock 实现
// 更新配音信息
8.3.7.4 删除配音
// 请求
DELETE /api/v1/voiceovers/:voiceoverId

// 响应
type DeleteVoiceoverResponse = ApiSuccessResponse<{ id: string }>;

// Mock 实现
// 从 Mock 数据中删除配音

8.3.8 AI 生成 API

8.3.8.1 图片生成(图片提示词)
// 请求
POST /api/v1/ai/generate-image
Body: {
  prompt: string;
  model?: string;
  parameters?: {
    width?: number;
    height?: number;
    style?: string;
    negativePrompt?: string;
  };
  storyboardId?: string;
}

// 响应(同步,快速生成)
type GenerateImageResponse = ApiSuccessResponse<{
  imageUrl: string;
  thumbnailUrl: string;
}>;

// 响应(异步,复杂生成)
type GenerateImageAsyncResponse = ApiSuccessResponse<{
  jobId: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  result?: {
    imageUrl: string;
    thumbnailUrl: string;
  };
}>;

// Mock 实现
// 返回模拟的图片 URL,延迟 1-3 秒模拟异步
8.3.8.2 角度变换
// 请求
POST /api/v1/ai/transform-angle
Body: {
  imageUrl: string;  // 原图 URL
  angle: 'front' | 'side' | 'back' | 'top' | 'bottom';
  model?: string;
}

// 响应
type TransformAngleResponse = ApiSuccessResponse<{
  imageUrl: string;
  thumbnailUrl: string;
}>;

// Mock 实现
// 返回模拟的变换后图片 URL
8.3.8.3 镜头调整
// 请求
POST /api/v1/ai/adjust-lens
Body: {
  imageUrl: string;
  lensType: 'wide' | 'normal' | 'telephoto' | 'macro';
  model?: string;
}

// 响应
type AdjustLensResponse = ApiSuccessResponse<{
  imageUrl: string;
  thumbnailUrl: string;
}>;

// Mock 实现
// 返回模拟的调整后图片 URL
8.3.8.4 生成分镜素材
// 请求
POST /api/v1/ai/generate-storyboard-assets
Body: {
  storyboardId: string;
  prompt: string;
  assetTypes: ('character' | 'scene' | 'prop')[];
  model?: string;
}

// 响应
type GenerateStoryboardAssetsResponse = ApiSuccessResponse<{
  jobId: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  result?: {
    characters: ResourceItem[];
    scenes: ResourceItem[];
    props: ResourceItem[];
  };
}>;

// Mock 实现
// 返回模拟的资源列表
8.3.8.5 生成资源素材
// 请求
POST /api/v1/ai/generate-resource
Body: {
  type: 'character' | 'scene' | 'prop';
  prompt: string;
  storyboardId?: string;
  model?: string;
}

// 响应
type GenerateResourceResponse = ApiSuccessResponse<ResourceItem>;

// Mock 实现
// 返回模拟的资源项
8.3.8.6 生成视频
// 请求
POST /api/v1/ai/generate-video
Body: {
  type: 'img2video' | 'text2video' | 'keyframe' | 'fusion' | 'replace' | 'real';
  prompt?: string;
  imageUrl?: string;  // 图生视频需要
  startFrame?: string;  // 首尾帧视频需要
  endFrame?: string;   // 首尾帧视频需要
  model?: string;
  storyboardId?: string;
}

// 响应(异步)
type GenerateVideoResponse = ApiSuccessResponse<{
  jobId: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  result?: {
    videoId: string;
    videoUrl: string;
    thumbnailUrl: string;
    duration: number;
  };
  progress?: number;  // 0-100
}>;

// Mock 实现
// 返回模拟的任务 ID,模拟进度更新
8.3.8.7 生成音效
// 请求
POST /api/v1/ai/generate-sound
Body: {
  prompt: string;
  duration?: number;  // 音效时长(秒)
  model?: string;
}

// 响应(异步)
type GenerateSoundResponse = ApiSuccessResponse<{
  jobId: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  result?: {
    soundEffectId: string;
    audioUrl: string;
    duration: number;
  };
}>;

// Mock 实现
// 返回模拟的音效 ID 和 URL
8.3.8.8 生成字幕
// 请求
POST /api/v1/ai/generate-subtitle
Body: {
  videoId?: string;
  prompt?: string;
  startTime?: number;
  endTime?: number;
  model?: string;
}

// 响应
type GenerateSubtitleResponse = ApiSuccessResponse<Subtitle>;

// Mock 实现
// 返回模拟的字幕项
8.3.8.9 生成配音
// 请求
POST /api/v1/ai/generate-voiceover
Body: {
  text: string;
  voiceType?: string;
  startTime?: number;
  endTime?: number;
  model?: string;
}

// 响应(异步)
type GenerateVoiceoverResponse = ApiSuccessResponse<{
  jobId: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  result?: {
    voiceoverId: string;
    audioUrl: string;
    duration: number;
  };
}>;

// Mock 实现
// 返回模拟的配音 ID 和 URL
8.3.8.10 查询 AI 任务状态
// 请求
GET /api/v1/ai/jobs/:jobId

// 响应
type GetAIJobResponse = ApiSuccessResponse<{
  jobId: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  progress?: number;
  result?: any;
  error?: string;
}>;

// Mock 实现
// 根据任务 ID 返回任务状态

8.3.9 时间轴管理 API

8.3.9.1 获取项目时间轴
// 请求
GET /api/v1/projects/:projectId/timeline

// 响应
type GetTimelineResponse = ApiSuccessResponse<{
  tracks: TimelineTrack[];
  items: TimelineItem[];
}>;

// Mock 实现
// 返回项目的时间轴配置
8.3.9.2 更新时间轴
// 请求
PUT /api/v1/projects/:projectId/timeline
Body: {
  tracks: TimelineTrack[];
  items: TimelineItem[];
}

// 响应
type UpdateTimelineResponse = ApiSuccessResponse<{
  tracks: TimelineTrack[];
  items: TimelineItem[];
}>;

// Mock 实现
// 更新时间轴配置

8.3.10 其他功能 API

8.3.10.1 获取项目成员
// 请求
GET /api/v1/projects/:projectId/members

// 响应
type GetProjectMembersResponse = ApiSuccessResponse<{
  members: Array<{
    id: string;
    name: string;
    avatar?: string;
    role: 'owner' | 'editor' | 'viewer';
    email?: string;
  }>;
}>;

// Mock 实现
// 返回模拟的成员列表
8.3.10.2 获取项目备注
// 请求
GET /api/v1/projects/:projectId/notes

// 响应
type GetProjectNotesResponse = ApiSuccessResponse<{
  notes: Array<{
    id: string;
    content: string;
    authorId: string;
    createdAt: number;
    updatedAt: number;
  }>;
}>;

// Mock 实现
// 返回项目备注列表
8.3.10.3 更新项目备注
// 请求
PUT /api/v1/projects/:projectId/notes
Body: {
  content: string;
}

// 响应
type UpdateProjectNotesResponse = ApiSuccessResponse<{
  id: string;
  content: string;
  updatedAt: number;
}>;

// Mock 实现
// 更新项目备注
8.3.10.4 获取通知列表
// 请求
GET /api/v1/notifications
Query Parameters:
  - unreadOnly?: boolean;
  - page?: number;
  - pageSize?: number;

// 响应
type GetNotificationsResponse = ApiPaginatedResponse<{
  id: string;
  type: 'project' | 'comment' | 'mention' | 'system';
  title: string;
  content: string;
  read: boolean;
  createdAt: number;
}>;

// Mock 实现
// 返回模拟的通知列表

8.4 API 调用封装

8.4.1 API Client 实现

// src/services/api/client.ts
class ApiClient {
  private baseURL: string;
  private token: string | null = null;

  constructor(baseURL: string) {
    this.baseURL = baseURL;
  }

  setToken(token: string) {
    this.token = token;
  }

  private async request<T>(
    method: string,
    endpoint: string,
    data?: any,
  ): Promise<T> {
    const url = `${this.baseURL}${endpoint}`;
    const headers: HeadersInit = {
      "Content-Type": "application/json",
    };

    if (this.token) {
      headers["Authorization"] = `Bearer ${this.token}`;
    }

    const config: RequestInit = {
      method,
      headers,
    };

    if (data && method !== "GET") {
      config.body = JSON.stringify(data);
    }

    const response = await fetch(url, config);
    const result = await response.json();

    if (!result.success) {
      throw new ApiError(result.error);
    }

    return result.data;
  }

  get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
    const queryString = params
      ? "?" + new URLSearchParams(params).toString()
      : "";
    return this.request<T>("GET", endpoint + queryString);
  }

  post<T>(endpoint: string, data?: any): Promise<T> {
    return this.request<T>("POST", endpoint, data);
  }

  put<T>(endpoint: string, data?: any): Promise<T> {
    return this.request<T>("PUT", endpoint, data);
  }

  delete<T>(endpoint: string): Promise<T> {
    return this.request<T>("DELETE", endpoint);
  }
}

export const apiClient = new ApiClient(
  import.meta.env.VITE_API_BASE_URL || "http://localhost:3000/api/v1",
);

8.4.2 Mock API 实现

// src/services/api/mockApi.ts
import { apiClient } from "./client";
import { mockData } from "../mockData";

// 判断是否使用 Mock
const USE_MOCK = import.meta.env.VITE_USE_MOCK === "true";

// Mock API 实现
export const mockApiClient = {
  // 项目相关
  getProjects: async (params?: any) => {
    if (USE_MOCK) {
      // 模拟延迟
      await new Promise((resolve) => setTimeout(resolve, 500));
      return mockData.projects;
    }
    return apiClient.get("/projects", params);
  },

  getProject: async (id: string) => {
    if (USE_MOCK) {
      await new Promise((resolve) => setTimeout(resolve, 300));
      return mockData.projects.find((p) => p.id === id);
    }
    return apiClient.get(`/projects/${id}`);
  },

  createProject: async (data: any) => {
    if (USE_MOCK) {
      await new Promise((resolve) => setTimeout(resolve, 500));
      const newProject = {
        ...data,
        id: `proj-${Date.now()}`,
        createdAt: Date.now(),
        updatedAt: Date.now(),
        storyboards: [],
      };
      mockData.projects.push(newProject);
      return newProject;
    }
    return apiClient.post("/projects", data);
  },

  // ... 其他 API 方法
};

8.4.3 API Hooks 封装

// src/hooks/useProject.ts
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { mockApiClient } from "../services/api/mockApi";

export const useProjects = (params?: any) => {
  return useQuery({
    queryKey: ["projects", params],
    queryFn: () => mockApiClient.getProjects(params),
  });
};

export const useProject = (id: string) => {
  return useQuery({
    queryKey: ["project", id],
    queryFn: () => mockApiClient.getProject(id),
    enabled: !!id,
  });
};

export const useCreateProject = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (data: any) => mockApiClient.createProject(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["projects"] });
    },
  });
};

// ... 其他 Hooks

8.5 环境配置

8.5.1 环境变量

# .env.development
VITE_API_BASE_URL=http://localhost:3000/api/v1
VITE_USE_MOCK=true

# .env.production
VITE_API_BASE_URL=https://api.jointo.ai/api/v1
VITE_USE_MOCK=false

8.5.2 API 切换机制

// src/services/api/index.ts
const isMock = import.meta.env.VITE_USE_MOCK === "true";

export const api = isMock ? mockApiClient : apiClient;

// 使用示例
import { api } from "@/services/api";

// 自动根据环境使用 Mock 或真实 API
const projects = await api.getProjects();

8.6 API 调用清单

8.6.1 需要实现 Mock 的 API(MVP 阶段)

功能模块 API 端点 方法 Mock 状态
项目管理 /api/v1/projects GET 需要 Mock
项目管理 /api/v1/projects POST 需要 Mock
项目管理 /api/v1/projects/:id GET 需要 Mock
项目管理 /api/v1/projects/:id PUT 需要 Mock
项目管理 /api/v1/projects/:id DELETE 需要 Mock
项目管理 /api/v1/projects/:id/export POST 需要 Mock
分镜管理 /api/v1/projects/:id/storyboards GET 需要 Mock
分镜管理 /api/v1/projects/:id/storyboards POST 需要 Mock
分镜管理 /api/v1/storyboards/:id GET 需要 Mock
分镜管理 /api/v1/storyboards/:id PUT 需要 Mock
分镜管理 /api/v1/storyboards/:id DELETE 需要 Mock
资源管理 /api/v1/resources GET 需要 Mock
资源管理 /api/v1/resources POST 需要 Mock
资源管理 /api/v1/resources/:id DELETE 需要 Mock
视频管理 /api/v1/videos GET 需要 Mock
视频管理 /api/v1/videos POST 需要 Mock
视频管理 /api/v1/videos/:id PUT 需要 Mock
视频管理 /api/v1/videos/:id DELETE 需要 Mock
音效管理 /api/v1/sound-effects GET 需要 Mock
音效管理 /api/v1/sound-effects POST 需要 Mock
音效管理 /api/v1/sound-effects/:id PUT 需要 Mock
音效管理 /api/v1/sound-effects/:id DELETE 需要 Mock
字幕管理 /api/v1/subtitles GET 需要 Mock
字幕管理 /api/v1/subtitles POST 需要 Mock
字幕管理 /api/v1/subtitles/:id PUT 需要 Mock
字幕管理 /api/v1/subtitles/:id DELETE 需要 Mock
配音管理 /api/v1/voiceovers GET 需要 Mock
配音管理 /api/v1/voiceovers POST 需要 Mock
配音管理 /api/v1/voiceovers/:id PUT 需要 Mock
配音管理 /api/v1/voiceovers/:id DELETE 需要 Mock
AI 生成 /api/v1/ai/generate-image POST 需要 Mock
AI 生成 /api/v1/ai/transform-angle POST 需要 Mock
AI 生成 /api/v1/ai/adjust-lens POST 需要 Mock
AI 生成 /api/v1/ai/generate-storyboard-assets POST 需要 Mock
AI 生成 /api/v1/ai/generate-resource POST 需要 Mock
AI 生成 /api/v1/ai/generate-video POST 需要 Mock
AI 生成 /api/v1/ai/generate-sound POST 需要 Mock
AI 生成 /api/v1/ai/generate-subtitle POST 需要 Mock
AI 生成 /api/v1/ai/generate-voiceover POST 需要 Mock
AI 生成 /api/v1/ai/jobs/:id GET 需要 Mock
时间轴 /api/v1/projects/:id/timeline GET 需要 Mock
时间轴 /api/v1/projects/:id/timeline PUT 需要 Mock
其他 /api/v1/projects/:id/members GET 需要 Mock
其他 /api/v1/projects/:id/notes GET 需要 Mock
其他 /api/v1/projects/:id/notes PUT 需要 Mock
其他 /api/v1/notifications GET 需要 Mock

8.6.2 前端纯状态(无需 API)

功能 说明
Tab 切换 前端状态管理
面板展开/收起 前端状态管理
弹窗显示/隐藏 前端状态管理
选中状态 前端状态管理
预览窗口缩放 前端状态管理
时间轴缩放/滚动 前端状态管理
播放控制(模拟) 前端状态管理
新手引导状态 localStorage

9. 技术方案

8.1 技术栈选择

8.1.1 核心框架

  • React 19:使用最新版本的 React
  • TypeScript:类型安全,提升开发效率
  • Vite:快速构建工具,开发体验好

8.1.2 状态管理

  • ZustandJotai:轻量级状态管理
  • React Context + useReducer:如果状态不复杂

8.1.3 UI 组件库

  • 自定义组件:完全按照 Figma 设计稿实现
  • 图标库lucide-react(与设计稿中使用的图标库一致)
  • 工具库
    • clsxclassnames:条件类名
    • react-dnd:拖拽功能(时间轴拖拽,可选)

8.1.4 样式方案

  • Tailwind CSS:推荐,快速开发,易于维护
  • CSS Modules:如果偏好传统 CSS
  • Styled Components:如果偏好 CSS-in-JS

8.1.5 工具库

  • 日期时间dayjsdate-fns
  • HTTP 请求axiosfetch
  • 表单处理react-hook-form(如果需要复杂表单)
  • 动画framer-motion 或 CSS transitions

8.2 项目结构

jointo/
├── public/                 # 静态资源
│   ├── images/            # 图片资源
│   └── mock-data/         # Mock 数据文件
├── src/
│   ├── components/        # 组件
│   │   ├── layout/        # 布局组件
│   │   │   ├── TopBar.tsx
│   │   │   ├── LeftSidebar.tsx
│   │   │   ├── RightSidebar.tsx
│   │   │   └── Layout.tsx
│   │   ├── storyboard/    # 分镜相关组件
│   │   │   ├── StoryboardPanel.tsx
│   │   │   ├── StoryboardItem.tsx
│   │   │   └── StoryboardHeader.tsx
│   │   ├── preview/       # 预览相关组件
│   │   │   ├── PreviewPanel.tsx
│   │   │   └── PreviewControls.tsx
│   │   ├── timeline/      # 时间轴相关组件
│   │   │   ├── TimelinePanel.tsx
│   │   │   ├── TimelineTrack.tsx
│   │   │   ├── TimelineItem.tsx
│   │   │   └── TimeScale.tsx
│   │   ├── resource/      # 资源相关组件
│   │   │   ├── ResourcePanel.tsx
│   │   │   ├── ResourceGroup.tsx
│   │   │   └── ResourceTag.tsx
│   │   ├── video/         # 视频相关组件
│   │   │   ├── VideoPanel.tsx
│   │   │   └── VideoItem.tsx
│   │   ├── common/        # 通用组件
│   │   │   ├── Button.tsx
│   │   │   ├── Input.tsx
│   │   │   ├── Modal.tsx
│   │   │   ├── Tab.tsx
│   │   │   └── Toast.tsx
│   │   └── onboarding/   # 新手引导
│   │       └── OnboardingOverlay.tsx
│   ├── hooks/             # 自定义 Hooks
│   │   ├── useProject.ts
│   │   ├── useStoryboard.ts
│   │   ├── useTimeline.ts
│   │   └── useAIGenerate.ts
│   ├── store/             # 状态管理
│   │   ├── projectStore.ts
│   │   ├── storyboardStore.ts
│   │   ├── timelineStore.ts
│   │   └── uiStore.ts
│   ├── services/          # 服务层
│   │   ├── api/           # API 调用
│   │   │   ├── projectApi.ts
│   │   │   ├── aiApi.ts
│   │   │   └── mockApi.ts
│   │   └── storage/       # 本地存储
│   │       └── localStorage.ts
│   ├── types/             # TypeScript 类型
│   │   ├── project.ts
│   │   ├── storyboard.ts
│   │   └── timeline.ts
│   ├── utils/             # 工具函数
│   │   ├── timecode.ts
│   │   ├── format.ts
│   │   └── validation.ts
│   ├── styles/            # 全局样式
│   │   ├── globals.css
│   │   └── variables.css
│   ├── App.tsx            # 根组件
│   └── main.tsx           # 入口文件
├── .env                   # 环境变量
├── .gitignore
├── package.json
├── tsconfig.json
├── tailwind.config.js     # Tailwind 配置(如果使用)
└── vite.config.ts         # Vite 配置

8.3 关键实现细节

8.3.1 时间轴实现

  • 使用 Canvas 或 SVG 绘制时间刻度(性能更好)
  • 或使用 CSS + 虚拟滚动(实现简单)
  • 支持水平滚动和缩放
  • 支持拖拽和调整时间块(可选)

8.3.2 预览窗口实现

  • 使用 <img> 标签显示预览图
  • 支持缩放(CSS transform)
  • 支持适应/填充模式切换
  • 支持点击放大查看(可选)

8.3.3 AI 功能实现

  • 统一封装 AI 请求函数
  • 使用 Promise 模拟异步请求
  • 返回 mock 数据
  • 显示加载状态和结果反馈

8.3.4 状态同步

  • 项目切换时,同步更新所有相关状态
  • 分镜选择时,同步更新预览、资源、时间轴
  • 时间轴操作时,同步更新播放位置

8.4 性能优化

8.4.1 组件优化

  • 使用 React.memo 避免不必要的重渲染
  • 使用 useMemouseCallback 优化计算和函数
  • 虚拟滚动处理长列表

8.4.2 资源优化

  • 图片懒加载
  • 代码分割(路由级别或组件级别)
  • 压缩静态资源

8.4.3 状态优化

  • 按需加载数据
  • 缓存常用数据
  • 防抖和节流处理频繁操作

9. 技术方案

10.1 性能要求

  • 首屏加载时间:< 3 秒(不含真实 AI 请求)
  • 交互响应时间:< 100ms(点击、切换等操作)
  • 页面滚动帧率:≥ 60 FPS
  • 内存使用:合理控制,避免内存泄漏

10.2 兼容性要求

  • 浏览器:Chrome、Edge、Safari 最新版本
  • 屏幕分辨率:1920x1080 及以上(主要适配)
  • 操作系统:Windows、macOS、Linux

10.3 可用性要求

  • 中英文混排:界面不破版,文字正确显示
  • 响应式布局:适配不同屏幕尺寸(可选)
  • 错误处理:友好的错误提示和处理
  • 加载状态:清晰的加载指示

10.4 可维护性要求

  • 代码规范:遵循 ESLint、Prettier 规范
  • 类型安全:完整的 TypeScript 类型定义
  • 组件文档:关键组件添加注释
  • 测试覆盖:关键功能添加单元测试(可选)

10.5 可扩展性要求

  • API 接口:预留后端 API 接口,易于切换
  • 插件化:AI 功能模块化,易于扩展
  • 配置化:关键参数可配置

10. 非功能需求

11.1 第一阶段:基础架构搭建(1-2 天)

目标:搭建项目基础结构和核心布局

任务清单

  • 初始化 React + TypeScript + Vite 项目
  • 配置 Tailwind CSS 或 CSS Modules
  • 配置 ESLint、Prettier
  • 创建基础目录结构
  • 实现 Layout 组件(TopBar、LeftSidebar、RightSidebar、CenterArea)
  • 实现基础样式和变量
  • 配置路由(如果需要)

验收标准

  • 项目可以正常运行
  • 基础布局结构完整
  • 样式系统配置完成

11.2 第二阶段:静态数据展示(2-3 天)

目标:填充所有静态数据和 UI 元素

任务清单

  • 创建 Mock 数据文件
  • 实现项目列表组件
  • 实现分镜列表组件(6 个分镜)
  • 实现预览窗口组件
  • 实现时间轴组件(静态显示)
  • 实现资源面板组件
  • 实现视频/音效/字幕/配音面板组件
  • 实现 AI 输入区组件
  • 实现所有按钮、图标、文本内容

验收标准

  • 所有 UI 元素完整显示
  • 所有文本内容正确
  • 所有数据正确展示

11.3 第三阶段:交互逻辑实现(3-4 天)

目标:实现所有交互逻辑和状态管理

任务清单

  • 实现状态管理(Zustand 或 Context)
  • 实现项目切换逻辑
  • 实现分镜选择逻辑
  • 实现 Tab 切换逻辑
  • 实现预览窗口交互(缩放、模式切换)
  • 实现播放控制逻辑
  • 实现时间轴交互(选中、滚动、缩放)
  • 实现资源添加/删除逻辑
  • 实现分镜编辑逻辑(标题、描述)
  • 实现插入新分镜逻辑

验收标准

  • 所有交互功能正常工作
  • 状态同步正确
  • 用户体验流畅

11.4 第四阶段:AI 功能和弹窗(2-3 天)

目标:实现所有 AI 功能入口和弹窗

任务清单

  • 实现 AI 生成弹窗组件
  • 封装 AI API 调用(mock)
  • 实现图片提示词功能
  • 实现角度变换功能
  • 实现镜头调整功能
  • 实现所有 AI 生成按钮(分镜、资源、视频、音效、字幕、配音)
  • 实现模型选择器
  • 实现 Toast 提示组件
  • 实现加载状态显示

验收标准

  • 所有 AI 功能入口可点击
  • 弹窗显示和交互正常
  • Mock 数据返回正确

11.5 第五阶段:新手引导和全局功能(1-2 天)

目标:实现新手引导和其他全局功能

任务清单

  • 实现新手引导浮层组件
  • 实现引导步骤切换逻辑
  • 实现引导跳过和持久化
  • 实现 Cookie 提示
  • 实现权限管理弹窗(mock)
  • 实现项目备注功能
  • 实现设置弹窗(mock)
  • 实现通知功能(mock)

验收标准

  • 新手引导流程完整
  • 全局功能正常工作
  • 持久化功能正常

11.6 第六阶段:优化和打磨(2-3 天)

目标:优化性能、修复问题、完善细节

任务清单

  • 性能优化(组件 memo、虚拟滚动等)
  • 交互细节优化(动画、过渡效果)
  • 响应式适配(可选)
  • 错误处理和边界情况
  • 代码重构和优化
  • 添加注释和文档
  • 测试和修复 bug

验收标准

  • 性能指标达标
  • 无明显 bug
  • 代码质量良好
  • 用户体验流畅

11.7 总计时间估算

  • 第一阶段:1-2 天
  • 第二阶段:2-3 天
  • 第三阶段:3-4 天
  • 第四阶段:2-3 天
  • 第五阶段:1-2 天
  • 第六阶段:2-3 天

总计:11-17 个工作日(约 2.5-3.5 周)


附录

A. 设计稿参考

  • Figma 文件https://www.figma.com/make/xgPuMR3GZzHpYh0RZJdiYK/kaidong.ai?p=f&fullscreen=1
  • 密码0592

B. 关键文本内容汇总

B.1 分镜描述文本

  1. 分镜1:"清晨的阳光照进窗户,主人公在床上慢慢睁开眼睛,开始新的一天。窗外传来鸟鸣声,窗帘随着微风轻轻飘动。"
  2. 分镜2:"主人公来到厨房,打开冰箱,拿出牛奶和面包,开始准备早餐。厨房里充满了温馨的气息,阳光从窗户洒进来。"
  3. 分镜3:"坐在餐桌前,主人公一边享用早餐,一边浏览手机上的新闻。桌上摆放着精致的餐具和一杯热气腾腾的咖啡。"
  4. 分镜4:"吃完早餐,主人公整理好餐具,将碗筷放进洗碗池,打开水龙头清洗。流水声和餐具碰撞的声音交织在一起。"
  5. 分镜5:"回到房间,主人公打开衣柜,精心挑选今天要穿的衣服,换好衣服后对着镜子整理仪容。镜子里映出满意的笑容。"
  6. 分镜6:"拿起背包和钥匙,主人公走向门口,回头看了一眼房间,打开门走出去,开始新一天的旅程。门在身后轻轻关上。"

B.2 AI 提示词示例

  • 图片提示词示例1:"一位中年男性,穿着正装,站在办公室里"
  • 图片提示词示例2:"背景是现代化的办公环境,玻璃窗外是城市景观"
  • 输入框示例:"@孙悟空 拿着/金箍棒 在 #火焰山 跟@牛魔王 手持/芭蕉扇 互相攻击。"

B.3 新手引导文本

  • 步骤1标题:"项目与素材管理"
  • 步骤1描述:"在这里您可以新增、查看和管理项目,同时可以查看和管理项目中的所有素材资源。"

C. 待补充内容

  1. 新手引导步骤 2-4:需要补充完整内容
  2. 项目设置选项:需要补充详细设置项
  3. 权限管理功能:需要补充详细权限选项
  4. 导出功能:需要补充导出选项和格式

D. 变更记录

  • v2.0 (2025-01-27):完整详细版,包含所有 UI/UX 细节和交互逻辑
  • v1.0 (2025-01-27):初始版本,基础功能需求

文档结束

本文档将作为开发指南,在开发过程中可根据实际情况进行调整和补充。