# Jointo(jointo)产品需求开发文档(完整版) > **目标**:用 React 前端完整还原 Figma Make 设计稿的所有 UI 元素、交互逻辑和功能细节。 > **文档版本**:v2.0 - 完整详细版 > **项目域名**:https://www.jointo.ai --- ## 目录 1. [产品概述](#1-产品概述) 2. [目标与范围](#2-目标与范围) 3. [用户与使用场景](#3-用户与使用场景) 4. [整体布局架构](#4-整体布局架构) 5. [详细功能需求](#5-详细功能需求) 6. [UI/UX 交互细节](#6-uiux-交互细节) 7. [数据模型](#7-数据模型) 8. [API 接口规范](#8-api-接口规范) 9. [技术方案](#9-技术方案) 10. [非功能需求](#10-非功能需求) 11. [开发迭代计划](#11-开发迭代计划) --- ## 1. 产品概述 ### 1.1 产品定位 **Jointo**是一个面向视频创作者、运营人员和营销团队的 AI 驱动视频制作平台。提供从分镜策划、素材管理、视频剪辑到音效/字幕/配音的一体化工作流程。 ### 1.2 核心价值 - **全流程覆盖**:分镜 → 资源 → 视频 → 音效 → 字幕 → 配音 → 导出 - **AI 能力集成**:大量使用 AI 生成和辅助功能,降低制作门槛 - **协作支持**:支持多人协同编辑和项目管理 - **实时预览**:所见即所得的预览体验 ### 1.3 产品名称 - **中文**:Jointo - **英文/文件标识**:jointo - **域名**:https://www.jointo.ai --- ## 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 时间刻度 **刻度范围**:`0s` 到 `60s` **显示方式**: - 每秒一个刻度标记 - 每 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 Cookie 提示(Consent Manager) #### 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 核心数据类型 ```typescript // 项目类型 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; storyboardId?: string; }; // AI 生成响应 type AIGenerateResponse = { success: boolean; data?: any; error?: string; jobId?: string; // 异步任务 ID }; ``` ### 7.2 状态管理数据结构 ```typescript // 应用全局状态 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 数据示例 ```typescript // 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 统一响应结构 ```typescript // 成功响应 type ApiSuccessResponse = { success: true; data: T; message?: string; }; // 错误响应 type ApiErrorResponse = { success: false; error: { code: string; message: string; details?: any; }; }; // 分页响应 type ApiPaginatedResponse = { success: true; data: T[]; pagination: { page: number; pageSize: number; total: number; totalPages: number; }; }; ``` #### 8.1.3 错误码规范 ```typescript 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 获取项目列表 ```typescript // 请求 GET /api/v1/projects Query Parameters: - type?: 'mine' | 'collab' // 项目类型,不传则返回全部 - page?: number // 页码,默认 1 - pageSize?: number // 每页数量,默认 20 // 响应 type GetProjectsResponse = ApiPaginatedResponse; // Mock 实现 // 返回本地 Mock 数据,格式与真实 API 一致 ``` ##### 8.3.1.2 获取项目详情 ```typescript // 请求 GET /api/v1/projects/:projectId // 响应 type GetProjectResponse = ApiSuccessResponse; // Mock 实现 // 从 Mock 数据中查找对应项目 ``` ##### 8.3.1.3 创建项目 ```typescript // 请求 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; // Mock 实现 // 生成新项目 ID,添加到 Mock 数据列表 ``` ##### 8.3.1.4 更新项目 ```typescript // 请求 PUT /api/v1/projects/:projectId Body: { name?: string; description?: string; settings?: ProjectSettings; } // 响应 type UpdateProjectResponse = ApiSuccessResponse; // Mock 实现 // 更新 Mock 数据中对应项目 ``` ##### 8.3.1.5 删除项目 ```typescript // 请求 DELETE /api/v1/projects/:projectId // 响应 type DeleteProjectResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除对应项目 ``` ##### 8.3.1.6 导出项目 ```typescript // 请求 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 获取项目分镜列表 ```typescript // 请求 GET /api/v1/projects/:projectId/storyboards // 响应 type GetStoryboardsResponse = ApiSuccessResponse; // Mock 实现 // 返回项目下的所有分镜 ``` ##### 8.3.2.2 获取分镜详情 ```typescript // 请求 GET /api/v1/storyboards/:storyboardId // 响应 type GetStoryboardResponse = ApiSuccessResponse; // Mock 实现 // 从 Mock 数据中查找对应分镜 ``` ##### 8.3.2.3 创建分镜 ```typescript // 请求 POST /api/v1/projects/:projectId/storyboards Body: { title: string; description?: string; order?: number; // 插入位置,不传则追加到最后 } // 响应 type CreateStoryboardResponse = ApiSuccessResponse; // Mock 实现 // 生成新分镜 ID,插入到指定位置 ``` ##### 8.3.2.4 更新分镜 ```typescript // 请求 PUT /api/v1/storyboards/:storyboardId Body: { title?: string; description?: string; startTime?: number; endTime?: number; order?: number; } // 响应 type UpdateStoryboardResponse = ApiSuccessResponse; // Mock 实现 // 更新 Mock 数据中对应分镜 ``` ##### 8.3.2.5 删除分镜 ```typescript // 请求 DELETE /api/v1/storyboards/:storyboardId // 响应 type DeleteStoryboardResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除对应分镜 ``` ##### 8.3.2.6 更新分镜资源 ```typescript // 请求 PUT /api/v1/storyboards/:storyboardId/resources Body: { characters?: ResourceItem[]; scenes?: ResourceItem[]; props?: ResourceItem[]; videos?: string[]; // 视频 ID 列表 } // 响应 type UpdateStoryboardResourcesResponse = ApiSuccessResponse; // Mock 实现 // 更新分镜的资源列表 ``` #### 8.3.3 资源管理 API ##### 8.3.3.1 获取资源列表 ```typescript // 请求 GET /api/v1/resources Query Parameters: - type?: 'character' | 'scene' | 'prop'; - storyboardId?: string; - page?: number; - pageSize?: number; // 响应 type GetResourcesResponse = ApiPaginatedResponse; // Mock 实现 // 返回资源列表,支持筛选 ``` ##### 8.3.3.2 上传资源 ```typescript // 请求 POST /api/v1/resources Content-Type: multipart/form-data Body: { file: File; name: string; type: 'character' | 'scene' | 'prop'; storyboardId?: string; } // 响应 type UploadResourceResponse = ApiSuccessResponse; // Mock 实现 // 生成资源 ID 和 URL,保存到 Mock 数据 ``` ##### 8.3.3.3 删除资源 ```typescript // 请求 DELETE /api/v1/resources/:resourceId // 响应 type DeleteResourceResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除资源 ``` #### 8.3.4 视频管理 API ##### 8.3.4.1 获取视频列表 ```typescript // 请求 GET /api/v1/videos Query Parameters: - projectId?: string; - storyboardId?: string; - page?: number; - pageSize?: number; // 响应 type GetVideosResponse = ApiPaginatedResponse; // Mock 实现 // 返回视频列表 ``` ##### 8.3.4.2 创建视频 ```typescript // 请求 POST /api/v1/videos Body: { name: string; type: 'img2video' | 'text2video' | 'keyframe' | 'fusion' | 'replace' | 'real'; storyboardId?: string; startTime?: number; endTime?: number; } // 响应 type CreateVideoResponse = ApiSuccessResponse; // Mock 实现 // 生成视频 ID,添加到 Mock 数据 ``` ##### 8.3.4.3 更新视频 ```typescript // 请求 PUT /api/v1/videos/:videoId Body: { name?: string; startTime?: number; endTime?: number; thumbnailUrl?: string; } // 响应 type UpdateVideoResponse = ApiSuccessResponse; // Mock 实现 // 更新视频信息 ``` ##### 8.3.4.4 删除视频 ```typescript // 请求 DELETE /api/v1/videos/:videoId // 响应 type DeleteVideoResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除视频 ``` #### 8.3.5 音效管理 API ##### 8.3.5.1 获取音效列表 ```typescript // 请求 GET /api/v1/sound-effects Query Parameters: - projectId?: string; - page?: number; - pageSize?: number; // 响应 type GetSoundEffectsResponse = ApiPaginatedResponse; // Mock 实现 // 返回音效列表 ``` ##### 8.3.5.2 创建音效 ```typescript // 请求 POST /api/v1/sound-effects Body: { name: string; startTime: number; endTime: number; volume?: number; audioUrl?: string; // 如果上传文件 } // 响应 type CreateSoundEffectResponse = ApiSuccessResponse; // Mock 实现 // 生成音效 ID,添加到 Mock 数据 ``` ##### 8.3.5.3 更新音效 ```typescript // 请求 PUT /api/v1/sound-effects/:soundEffectId Body: { name?: string; startTime?: number; endTime?: number; volume?: number; } // 响应 type UpdateSoundEffectResponse = ApiSuccessResponse; // Mock 实现 // 更新音效信息 ``` ##### 8.3.5.4 删除音效 ```typescript // 请求 DELETE /api/v1/sound-effects/:soundEffectId // 响应 type DeleteSoundEffectResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除音效 ``` #### 8.3.6 字幕管理 API ##### 8.3.6.1 获取字幕列表 ```typescript // 请求 GET /api/v1/subtitles Query Parameters: - projectId?: string; - page?: number; - pageSize?: number; // 响应 type GetSubtitlesResponse = ApiPaginatedResponse; // Mock 实现 // 返回字幕列表 ``` ##### 8.3.6.2 创建字幕 ```typescript // 请求 POST /api/v1/subtitles Body: { text: string; startTime: number; endTime: number; style?: SubtitleStyle; } // 响应 type CreateSubtitleResponse = ApiSuccessResponse; // Mock 实现 // 生成字幕 ID,添加到 Mock 数据 ``` ##### 8.3.6.3 更新字幕 ```typescript // 请求 PUT /api/v1/subtitles/:subtitleId Body: { text?: string; startTime?: number; endTime?: number; style?: SubtitleStyle; } // 响应 type UpdateSubtitleResponse = ApiSuccessResponse; // Mock 实现 // 更新字幕信息 ``` ##### 8.3.6.4 删除字幕 ```typescript // 请求 DELETE /api/v1/subtitles/:subtitleId // 响应 type DeleteSubtitleResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除字幕 ``` #### 8.3.7 配音管理 API ##### 8.3.7.1 获取配音列表 ```typescript // 请求 GET /api/v1/voiceovers Query Parameters: - projectId?: string; - page?: number; - pageSize?: number; // 响应 type GetVoiceoversResponse = ApiPaginatedResponse; // Mock 实现 // 返回配音列表 ``` ##### 8.3.7.2 创建配音 ```typescript // 请求 POST /api/v1/voiceovers Body: { text: string; startTime: number; endTime: number; voiceType?: string; volume?: number; } // 响应 type CreateVoiceoverResponse = ApiSuccessResponse; // Mock 实现 // 生成配音 ID,添加到 Mock 数据 ``` ##### 8.3.7.3 更新配音 ```typescript // 请求 PUT /api/v1/voiceovers/:voiceoverId Body: { text?: string; startTime?: number; endTime?: number; voiceType?: string; volume?: number; } // 响应 type UpdateVoiceoverResponse = ApiSuccessResponse; // Mock 实现 // 更新配音信息 ``` ##### 8.3.7.4 删除配音 ```typescript // 请求 DELETE /api/v1/voiceovers/:voiceoverId // 响应 type DeleteVoiceoverResponse = ApiSuccessResponse<{ id: string }>; // Mock 实现 // 从 Mock 数据中删除配音 ``` #### 8.3.8 AI 生成 API ##### 8.3.8.1 图片生成(图片提示词) ```typescript // 请求 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 角度变换 ```typescript // 请求 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 镜头调整 ```typescript // 请求 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 生成分镜素材 ```typescript // 请求 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 生成资源素材 ```typescript // 请求 POST /api/v1/ai/generate-resource Body: { type: 'character' | 'scene' | 'prop'; prompt: string; storyboardId?: string; model?: string; } // 响应 type GenerateResourceResponse = ApiSuccessResponse; // Mock 实现 // 返回模拟的资源项 ``` ##### 8.3.8.6 生成视频 ```typescript // 请求 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 生成音效 ```typescript // 请求 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 生成字幕 ```typescript // 请求 POST /api/v1/ai/generate-subtitle Body: { videoId?: string; prompt?: string; startTime?: number; endTime?: number; model?: string; } // 响应 type GenerateSubtitleResponse = ApiSuccessResponse; // Mock 实现 // 返回模拟的字幕项 ``` ##### 8.3.8.9 生成配音 ```typescript // 请求 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 任务状态 ```typescript // 请求 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 获取项目时间轴 ```typescript // 请求 GET /api/v1/projects/:projectId/timeline // 响应 type GetTimelineResponse = ApiSuccessResponse<{ tracks: TimelineTrack[]; items: TimelineItem[]; }>; // Mock 实现 // 返回项目的时间轴配置 ``` ##### 8.3.9.2 更新时间轴 ```typescript // 请求 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 获取项目成员 ```typescript // 请求 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 获取项目备注 ```typescript // 请求 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 更新项目备注 ```typescript // 请求 PUT /api/v1/projects/:projectId/notes Body: { content: string; } // 响应 type UpdateProjectNotesResponse = ApiSuccessResponse<{ id: string; content: string; updatedAt: number; }>; // Mock 实现 // 更新项目备注 ``` ##### 8.3.10.4 获取通知列表 ```typescript // 请求 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 实现 ```typescript // 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( method: string, endpoint: string, data?: any, ): Promise { 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(endpoint: string, params?: Record): Promise { const queryString = params ? "?" + new URLSearchParams(params).toString() : ""; return this.request("GET", endpoint + queryString); } post(endpoint: string, data?: any): Promise { return this.request("POST", endpoint, data); } put(endpoint: string, data?: any): Promise { return this.request("PUT", endpoint, data); } delete(endpoint: string): Promise { return this.request("DELETE", endpoint); } } export const apiClient = new ApiClient( import.meta.env.VITE_API_BASE_URL || "http://localhost:3000/api/v1", ); ``` #### 8.4.2 Mock API 实现 ```typescript // 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 封装 ```typescript // 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 环境变量 ```bash # .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 切换机制 ```typescript // 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 状态管理 - **Zustand** 或 **Jotai**:轻量级状态管理 - 或 **React Context + useReducer**:如果状态不复杂 #### 8.1.3 UI 组件库 - **自定义组件**:完全按照 Figma 设计稿实现 - **图标库**:`lucide-react`(与设计稿中使用的图标库一致) - **工具库**: - `clsx` 或 `classnames`:条件类名 - `react-dnd`:拖拽功能(时间轴拖拽,可选) #### 8.1.4 样式方案 - **Tailwind CSS**:推荐,快速开发,易于维护 - 或 **CSS Modules**:如果偏好传统 CSS - 或 **Styled Components**:如果偏好 CSS-in-JS #### 8.1.5 工具库 - **日期时间**:`dayjs` 或 `date-fns` - **HTTP 请求**:`axios` 或 `fetch` - **表单处理**:`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 预览窗口实现 - 使用 `` 标签显示预览图 - 支持缩放(CSS transform) - 支持适应/填充模式切换 - 支持点击放大查看(可选) #### 8.3.3 AI 功能实现 - 统一封装 AI 请求函数 - 使用 Promise 模拟异步请求 - 返回 mock 数据 - 显示加载状态和结果反馈 #### 8.3.4 状态同步 - 项目切换时,同步更新所有相关状态 - 分镜选择时,同步更新预览、资源、时间轴 - 时间轴操作时,同步更新播放位置 ### 8.4 性能优化 #### 8.4.1 组件优化 - 使用 `React.memo` 避免不必要的重渲染 - 使用 `useMemo` 和 `useCallback` 优化计算和函数 - 虚拟滚动处理长列表 #### 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):初始版本,基础功能需求 --- **文档结束** > 本文档将作为开发指南,在开发过程中可根据实际情况进行调整和补充。