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.
11 KiB
11 KiB
新建项目流程优化
日期:2026-02-08 类型:功能优化 影响范围:前端 - CreateProjectModal
变更概述
优化新建项目流程,移除项目类型选择,固定显示集数字段,新增共享资源选择功能。
背景
根据 ADR 02: 跨项目资源共享 的设计,用户在创建项目时:
- 项目内容类型(content_type)选择增加了用户认知负担
- 用户更关心资源共享而非项目分类
- 需要支持跨项目复用资源(角色、场景、道具)
变更内容
1. 移除项目类型选择
变更前:
<FormItem label="项目类型">
<Select value={projectType}>
<SelectItem value="ad">广告片</SelectItem>
<SelectItem value="movie">电影</SelectItem>
<SelectItem value="series">剧集</SelectItem>
{/* ... */}
</Select>
</FormItem>
变更后:
- 完全移除项目类型选择字段
- 表单 schema 不再包含
projectType - 后端 API 调用时不再传递
contentType参数
影响:
- 简化用户操作流程
- 减少认知负担
- 项目创建更聚焦于实际需求(集数、时长、资源)
2. 集数字段固定显示
变更前:
// 仅当项目类型为 series 或 anime 时显示
{showEpisodes && (
<FormItem label="集数">
<InputNumber value={episodes} />
</FormItem>
)}
变更后:
// 始终显示集数字段
<FormItem label="集数" required>
<InputNumber min={1} value={episodes ?? 1} />
</FormItem>
影响:
- 所有项目默认支持多集结构
- 单集项目设置为 1 集即可
- 统一项目数据模型
3. 新增共享资源选择功能
3.1 UI 结构
新增两个组件:
ResourceSelectorPanel.tsx- 资源选择面板(树形结构)SelectedResourcesDisplay.tsx- 已选资源展示(Tag 列表)
3.2 交互流程
┌─────────────────────────────────────────────────────────────────────┐
│ 项目属性 [关闭 ✕] │
├─────────────────────────────────────────────────────────────────────┤
│ 项目名称: [_____________________] │
│ 集数: [1] 单集计划时长: [60] [分钟▾] │
│ │
│ 共享资源 [选择资源] ◄─────┐ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ [角色] 孙悟空 (西游记第一季) [✕] │ │ │
│ │ [场景] 花果山 (西游记第一季) [✕] │ │ │
│ │ [道具] 金箍棒 (西游记第一季) [✕] │ │ │
│ └─────────────────────────────────────────────────────────────┘ │ │
│ [取消] [立即创建] │ │
└─────────────────────────────────────────────────────────────────────┘
│
点击"选择资源"展开右侧面板 ─────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────────┤
│ ┌────────────────────┐ │
│ │ 共享资源 │ │
│ ├────────────────────┤ │
│ │ [ ] ▶ 我的项目 │ │
│ │ [✓] ▼ 西游记系列 │ │
│ │ [✓] 孙悟空 │ │
│ │ [✓] 花果山 │ │
│ │ [✓] 金箍棒 │ │
│ │ │ │
│ │ 已选 3 项资源 │ │
│ └────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
3.3 数据结构
interface SharedResource {
id: string;
type: 'project' | 'folder' | 'character' | 'scene' | 'prop';
name: string;
parentName?: string;
count?: number;
}
3.4 核心特性
ResourceSelectorPanel:
- 树形结构展示项目/文件夹层级
- 支持多选(Checkbox)
- 显示资源统计(角色数、场景数、道具数)
- 展开/收起控制
- 滚动区域(ScrollArea)
SelectedResourcesDisplay:
- Tag 列表展示已选资源
- 不同资源类型不同颜色标识
- 项目/文件夹:蓝色/紫色
- 角色:绿色
- 场景:橙色
- 道具:粉色
- 支持删除单个资源
- 空状态提示
3.5 状态管理
// 共享资源面板展开状态
const [resourcePanelOpen, setResourcePanelOpen] = useState(false);
// 已选资源列表
const [selectedResources, setSelectedResources] = useState<SharedResource[]>([]);
// 资源选择回调
const handleResourceSelect = useCallback((resources: SharedResource[]) => {
setSelectedResources(resources);
}, []);
// 删除单个资源
const handleRemoveResource = useCallback((resourceId: string) => {
setSelectedResources(prev => prev.filter(r => r.id !== resourceId));
}, []);
4. 面板互斥逻辑
风格选择面板和资源选择面板互斥:
onClick={() => {
setResourcePanelOpen(prev => !prev);
setStylePanelOpen(false); // 关闭风格面板
}}
技术实现
文件变更
修改:
client/src/components/features/project/CreateProjectModal.tsx
新增:
client/src/components/features/project/ResourceSelectorPanel.tsxclient/src/components/features/project/SelectedResourcesDisplay.tsx
依赖组件
@/components/ui/checkbox- 复选框@/components/ui/scroll-area- 滚动区域lucide-react- 图标Share2- 共享资源按钮Folder- 项目/文件夹图标Users- 角色图标MapPin- 场景图标Package- 道具图标ChevronRight/ChevronDown- 展开/收起图标
表单验证调整
// 移除 projectType 字段
const createProjectSchema = z.object({
name: z.string().min(1).max(50),
folderId: z.string().optional(),
episodes: z.number().min(1), // 必填,不再可选
aspectRatio: z.enum([...]),
duration: z.string().min(1),
durationUnit: z.enum(['seconds', 'minutes']),
styleAndRoles: z.string().max(500).optional(),
});
API 调用调整
// 创建项目
const newProject = await createProject.mutateAsync({
name: data.name,
folderId: data.folderId?.startsWith('virtual-') ? undefined : data.folderId,
aspectRatio: data.aspectRatio,
plannedDuration: durationInSeconds,
styleAndCharacters,
// TODO: 待后端 API 支持
// sharedResources: selectedResources.map(r => ({ id: r.id, type: r.type })),
});
后续工作
Phase 1:Mock 数据替换为真实 API
当前状态:
- 资源树使用硬编码的 mock 数据
- 位置:
ResourceSelectorPanel.tsx第 26-87 行
待实现:
// 1. 创建 API 接口
// GET /api/v1/projects/shareable-resources
export async function getShareableResources(): Promise<ResourceTreeNode[]> {
const response = await apiClient.get('/projects/shareable-resources');
return response.data;
}
// 2. 使用 React Query 获取数据
const { data: resourceTree } = useQuery({
queryKey: ['shareable-resources'],
queryFn: getShareableResources,
enabled: resourcePanelOpen, // 仅展开时加载
});
Phase 2:保存共享关系
待实现:
// 创建项目时传递共享资源
const newProject = await createProject.mutateAsync({
// ... 其他字段
sharedResources: selectedResources.map(r => ({
resourceId: r.id,
resourceType: r.type,
})),
});
后端需求:
- 参考 ADR 02 第 6.1 节:新建项目时共享资源
- 接口:
POST /api/v1/projects - 请求体新增字段:
shared_resources: Array<{resource_id, resource_type, share_type}>
Phase 3:性能优化
优化方向:
-
虚拟滚动(资源多时)
- 使用
react-virtual或react-window - 优化大列表渲染性能
- 使用
-
搜索过滤
- 添加资源搜索框
- 支持按名称过滤
-
批量操作
- 全选/取消全选项目
- 全选/取消全选文件夹下所有资源
测试建议
1. 功能测试
- 创建项目时集数字段始终显示且默认为 1
- 点击"选择资源"按钮展开右侧面板
- 资源树正确展开/收起
- 多选资源后在左侧 Tag 列表正确显示
- 删除单个资源 Tag 正常工作
- 风格面板和资源面板互斥显示
- 弹窗宽度根据面板展开状态自适应
2. 边界测试
- 未选择资源时显示空状态提示
- 选择大量资源时滚动正常
- 关闭弹窗后清空选择状态
- 资源名称过长时截断显示
3. 样式测试
- 不同资源类型颜色区分明显
- 资源树缩进层级清晰
- Hover 状态过渡自然
- 暗色模式适配(如果有)
相关文档
变更记录
- 2026-02-08:初始版本 - 移除项目类型、新增共享资源选择