Files
gen2d/docs/frontend.md
wonder a603f5548c refactor: 前端重构为项目+任务双核心模型
- 新增 HomePage 项目画廊页,支持新建/删除工程
- 新增 ProjectDetailPage 三栏工作台(配置+生成+任务列表)
- 新增 CustomTagsEditor 支持自定义风格标签(custom: 前缀存入 kvPairs)
- 重构 project store 为 draft/commit 模式,支持手动保存/取消
- 新增 projectList store 管理工程列表
- 扩展 mock.ts 为多工程数据结构
- 扩展 api/project.ts 新增项目 CRUD API(mock-gated)
- 简化 ResultPage,仅展示素材预览
- 删除 GeneratePage、ProjectPage 及未使用的 hooks
- 更新 docs/ 文档(frontend.md、api.md、style-keys.md、_index.md)
2026-05-25 16:15:31 +08:00

353 lines
12 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 前端工程
## 技术栈
Vite 6 + React 18 + TypeScript + zustand + react-router-dom
| 类别 | 选型 | 说明 |
|------|------|------|
| 构建 | Vite 6 | 开发服务器端口 3000,`/api` 代理到 `localhost:8080` |
| UI 框架 | React 18 | 函数组件 + Hooks |
| 状态管理 | zustand | 轻量,支持 devtools 中间件 |
| 路由 | react-router-dom v6 | SPA 模式 |
| 实时通信 | HTTP 轮询 | 每 1.5s 轮询任务状态(WebSocket 待后端实现) |
| HTTP 请求 | fetch + 封装层 | 统一错误处理、响应解包 |
## 目录结构
```
frontend/src/
├── main.tsx # 入口
├── App.tsx # 根组件
├── api/ # API 封装层
│ ├── client.ts # fetch 封装:统一错误处理、响应解包(get/post/put/del)
│ ├── auth.ts # 注册/登录(真实后端调用)
│ ├── project.ts # 工程 CRUD + 风格 + 任务列表(mock 切换)
│ ├── generate.ts # POST /generate、GET /tasks/:taskId、GET /tasks/:taskId/assets
│ ├── prompt.ts # 提示词优化 + extractTags
│ ├── mock.ts # 多工程 Mock 数据 + 模拟 WebSocket 管线进度
│ └── types.ts # API 类型定义
├── stores/ # zustand stores
│ ├── auth.ts # 用户认证状态
│ ├── project.ts # 当前工程详情(含 draft/commit 风格编辑)
│ ├── projectList.ts # 工程列表(画廊页)
│ ├── task.ts # 任务草稿(生成表单状态)
│ ├── generation.ts # 生成状态(提交、轮询、结果)
│ ├── theme.ts # 主题切换(light/dark)
│ └── toast.ts # Toast 通知
├── pages/ # 页面级组件
│ ├── LoginPage.tsx # 登录页
│ ├── RegisterPage.tsx # 注册页
│ ├── HomePage.tsx # 项目画廊(工程列表 + 新建弹窗)
│ ├── ProjectDetailPage.tsx # 三栏工作台(配置 + 生成 + 任务列表)
│ └── ResultPage.tsx # 结果页(素材预览 + 下载)
├── components/ # 可复用组件
│ ├── Layout.tsx # 导航栏 + Outlet + ToastContainer
│ ├── StyleSelector.tsx # 预设风格选择器(pill 按钮)
│ ├── CustomTagsEditor.tsx # 自定义标签编辑器(可添加/删除)
│ ├── PromptEditor.tsx # 三段式提示词编辑器
│ ├── GenerateForm.tsx # 生成表单(素材类型 + 风格覆盖 + 提示词 + 参数)
│ ├── ProgressBar.tsx # 管线进度条
│ ├── AssetPreview.tsx # 素材预览
│ ├── ProjectCard.tsx # 画廊卡片
│ ├── CreateProjectModal.tsx # 新建工程弹窗
│ ├── ProjectConfigPanel.tsx # 左栏:工程配置编辑面板
│ ├── TaskListPanel.tsx # 右栏:任务列表面板
│ ├── StatusBadge.tsx # 状态徽标组件
│ ├── EmptyState.tsx # 空状态占位
│ ├── Skeleton.tsx # 加载骨架屏
│ └── Toast.tsx # Toast 通知容器
├── router/ # 路由定义
│ └── index.tsx
├── styles/ # 全局样式
│ └── global.css # 暗色/亮色主题 CSS 变量 + reset
└── utils/ # 工具函数
└── style.ts # 风格合并、预设分类、自定义标签工具
```
## 实现状态
| 模块 | 状态 | 说明 |
|------|------|------|
| API 封装层 | [x] | client.ts 统一 fetch 封装,auth.ts 真实调用,project/generate 使用 mock |
| Mock 层 | [x] | mock.ts 提供多工程 mock 数据 + 模拟 WebSocket 管线进度 |
| 认证流程 | [x] | 注册/登录/退出/token 持久化,真实后端对接 |
| zustand stores | [x] | auth/project/projectList/task/generation/theme/toast 七个 store |
| 页面 | [x] | 5 个页面(Login/Register/Home/ProjectDetail/Result) |
| 组件 | [x] | StyleSelector/CustomTagsEditor/PromptEditor/GenerateForm/ProgressBar/AssetPreview/ProjectCard/CreateProjectModal/ProjectConfigPanel/TaskListPanel/StatusBadge 等 |
| 路由 | [x] | 含 ProtectedRoute 守卫 |
| 自定义标签 | [x] | `custom:` 前缀存入 kvPairs,零后端改动 |
## 路由规划
| 路径 | 页面 | 说明 |
|------|------|------|
| `/` | HomePage | 项目画廊,展示所有工程 |
| `/projects/:projectId` | ProjectDetailPage | 三栏工作台(配置 + 生成 + 任务列表) |
| `/projects/:projectId/tasks/:taskId` | ResultPage | 素材预览 + 下载 |
## 组件树
```mermaid
graph TD
App --> Router
Router --> HomePage
Router --> ProjectDetailPage
Router --> ResultPage
HomePage --> ProjectCard["ProjectCard(工程卡片)"]
HomePage --> CreateProjectModal["CreateProjectModal(新建弹窗)"]
CreateProjectModal --> StyleSelector
CreateProjectModal --> CustomTagsEditor
ProjectDetailPage --> ProjectConfigPanel["ProjectConfigPanel(左栏配置)"]
ProjectDetailPage --> GenerateForm["GenerateForm(中间上半)"]
ProjectDetailPage --> ProgressBar["ProgressBar(中间下半)"]
ProjectDetailPage --> TaskListPanel["TaskListPanel(右栏任务)"]
ProjectConfigPanel --> StyleSelector2["StyleSelector"]
ProjectConfigPanel --> CustomTagsEditor2["CustomTagsEditor"]
TaskListPanel --> StatusBadge["StatusBadge"]
GenerateForm --> PromptEditor["PromptEditor"]
GenerateForm --> StyleSelector3["StyleSelector(任务覆盖)"]
ResultPage --> AssetPreview["AssetPreview"]
```
## 三栏工作台布局
ProjectDetailPage 采用 CSS Grid 三栏布局:
```
grid-template-columns: 260px 1fr 320px
```
| 区域 | 宽度 | 内容 |
|------|------|------|
| 左栏 | 260px | 工程名(可编辑)、预设风格选择器、自定义标签编辑器、保存/取消按钮 |
| 中间 | flex-1 | 上半:生成表单;下半:当前任务进度条(提交后显示) |
| 右栏 | 320px | 任务列表(所有状态),15 秒自动刷新 |
## 核心交互流程
### 项目管理流程
```mermaid
sequenceDiagram
actor User
participant HP as HomePage
participant API as 后端 API
User->>HP: 进入首页
HP->>API: GET /api/v1/projects
API-->>HP: 工程列表
HP->>HP: 画廊展示 ProjectCard
User->>HP: 点击「新建工程」
HP->>HP: 弹出 CreateProjectModal
User->>HP: 输入名称、选择风格、添加自定义标签
HP->>API: POST /api/v1/projects
API-->>HP: 新工程
HP->>HP: 跳转到 ProjectDetailPage
```
### 生成流程
```mermaid
sequenceDiagram
actor User
participant PDP as ProjectDetailPage
participant API as 后端 API
User->>PDP: 填写 prompt、选择素材类型
User->>PDP: 点击提交
PDP->>API: POST /api/v1/generate
API-->>PDP: 返回 taskId
PDP->>PDP: ProgressBar 显示进度
loop 轮询任务状态(1.5s)
PDP->>API: GET /api/v1/tasks/:taskId
API-->>PDP: 任务状态 + 进度
PDP->>PDP: 更新 ProgressBar
end
API-->>PDP: status = completed
PDP->>API: GET /api/v1/tasks/:taskId/assets
API-->>PDP: 素材列表
PDP->>PDP: 显示「查看结果」按钮
```
### 风格编辑流程(手动保存)
```mermaid
sequenceDiagram
actor User
participant PCP as ProjectConfigPanel
participant Store as project store
participant API as 后端 API
User->>PCP: 进入工程页
PCP->>Store: startEditing() — 复制 style 到 draftStyle
User->>PCP: 修改预设风格 / 添加自定义标签
PCP->>Store: updateDraft(key, value) — 更新 draftStyle
Store->>Store: hasUnsavedChanges = true
alt 点击保存
User->>PCP: 点击「保存」
PCP->>Store: commitDraft()
Store->>API: PUT /api/v1/projects/:id/style
Store->>API: PUT /api/v1/projects/:id(如名称变更)
Store->>Store: style = draftStyle, hasUnsavedChanges = false
else 点击取消
User->>PCP: 点击「取消」
PCP->>Store: discardDraft()
Store->>Store: draftStyle = style, hasUnsavedChanges = false
end
```
## 自定义标签
在预设风格分类之外,用户可添加自定义标签。标签存储在工程风格的 `kvPairs` 中,使用 `custom:` 前缀区分:
```json
{
"artStyle": "pixel",
"palette": "warm",
"custom:cel-shading": "true",
"custom:glow-effects": "true"
}
```
工具函数(`utils/style.ts`):
- `isCustomKey(key)` — 判断是否为自定义标签
- `getCustomTags(style)` — 提取自定义标签列表
- `addCustomTag(style, tag)` — 添加标签
- `removeCustomTag(style, tag)` — 删除标签
`extractTags()` 函数在提取标签时自动包含自定义标签值。
## 状态管理
### zustand stores
**projectList store** — 工程列表(HomePage)
```typescript
interface ProjectListState {
projects: Project[];
loading: boolean;
loadProjects: () => Promise<void>;
createProject: (name: string, style?: Record<string, string>) => Promise<Project>;
deleteProject: (projectId: string) => Promise<void>;
}
```
**project store** — 当前工程详情(ProjectDetailPage)
```typescript
interface ProjectState {
projectId: string;
name: string;
style: Record<string, string>;
draftStyle: Record<string, string>;
draftName: string;
hasUnsavedChanges: boolean;
loading: boolean;
loadProject: (projectId: string) => Promise<void>;
loadStyle: (projectId: string) => Promise<void>;
startEditing: () => void;
updateDraft: (key: string, value: string) => void;
setDraftStyle: (style: Record<string, string>) => void;
setDraftName: (name: string) => void;
discardDraft: () => void;
commitDraft: () => Promise<void>;
}
```
**task store** — 任务草稿
```typescript
interface TaskState {
prompt: string;
assetType: 'sprite' | 'background' | 'ui' | 'animation';
taskStyle: Record<string, string>;
params: TaskParams;
enableAI: boolean;
optimizedPrompt: string | null;
// ... setters, runOptimize, reset
}
```
**generation store** — 生成状态
```typescript
interface GenerationState {
taskId: string | null;
stage: PipelineStage | null;
progress: number;
status: 'idle' | 'submitting' | 'running' | 'completed' | 'failed';
retryCount: number;
rejectReason: string | null;
assets: Asset[];
error: string | null;
submit: (req: GenerateRequest) => Promise<void>;
reset: () => void;
}
```
## API 类型定义(api/types.ts)
```typescript
interface Project {
id: string;
name: string;
style: { kvPairs: Record<string, string> };
createdAt: string;
taskCount?: number;
lastActivityAt?: string;
}
interface CreateProjectRequest {
name: string;
style?: Record<string, string>;
}
interface Task {
id: string;
projectId: string;
prompt: string;
assetType: string;
status: 'pending' | 'submitted' | 'running' | 'completed' | 'failed';
stage?: PipelineStage;
progress?: number;
retryCount?: number;
error?: string | null;
createdAt: string;
updatedAt: string;
}
interface Asset {
id: string;
key: string;
url: string;
format: string;
width: number;
height: number;
metadata: {
frameWidth?: number;
frameHeight?: number;
frameCount?: number;
directions?: number;
};
}
```
## 预设风格键分类
前端 StyleSelector 以分类标签组织,完整键值表见 [预设风格键](style-keys.md)。
StyleSelector 两种使用场景:
1. **工程风格**(ProjectConfigPanel / CreateProjectModal):全量编辑,保存到后端
2. **任务覆盖**(GenerateForm):基于工程风格展示,仅记录差异