Skip to content

Data Model

以下数据模型覆盖当前 MVP 范围。后续功能的字段将在对应迭代中扩展。

核心实体

画布 (Canvas)

typescript
interface Canvas {
  id: string
  name: string
  nodes: CanvasNode[]
  edges: CanvasEdge[]
  viewport: { x: number, y: number, zoom: number }
  createdAt: string // ISO 8601
  updatedAt: string // ISO 8601
}
  • 存储:localStorage(MVP 阶段)
  • 主键:id(UUID)

节点 (Node)

typescript
type NodeType = 'text' | 'image' | 'video'

interface BaseNode<T = Record<string, unknown>> {
  id: string
  type: NodeType
  position: { x: number, y: number }
  data: T
}

type CanvasNode = TextNode | ImageNode | VideoNode

interface TextNode extends BaseNode<TextNodeData> {
  type: 'text'
}

interface ImageNode extends BaseNode<ImageNodeData> {
  type: 'image'
}

interface VideoNode extends BaseNode<VideoNodeData> {
  type: 'video'
}

TextNodeData

typescript
interface TextNodeData {
  title: string
  content: string // 富文本内容 (HTML)
  prompt: string // 用户输入的提示词
  model: string // 选择的 AI 模型
  variations: 1 | 2 | 4 // 变体数量
  status: NodeStatus
  result?: string // 生成结果文本
}

ImageNodeData

typescript
interface ImageNodeData {
  title: string
  imageUrl?: string // 上传/生成的图片 URL
  prompt: string
  model: string
  variations: 1 | 2 | 4 // 变体数量
  status: NodeStatus
  results?: string[] // 生成的图片 URL 列表(多变体时)
}

VideoNodeData(不含 variations)

typescript
interface VideoNodeData {
  title: string
  videoUrl?: string // 上传/生成的视频 URL
  duration?: number // 时长(秒)
  prompt: string
  model: string
  status: NodeStatus
  result?: string // 生成的视频 URL
}

节点状态

typescript
type NodeStatus = 'idle' | 'generating' | 'done' | 'error'

连线 (Edge)

序列化存储用独立接口,与 Vue Flow 的 Edge 类型解耦。加载画布时转换为 Vue Flow Edge,保存时转换回 CanvasEdge

typescript
interface CanvasEdge {
  id: string
  source: string // 源节点 ID
  target: string // 目标节点 ID
  sourceHandle?: string // 源连接点 ID
  targetHandle?: string // 目标连接点 ID
}

状态结构

Pinia Stores

canvasStore
├── canvases: Canvas[]              // 所有画布列表(Workspace 用)
├── currentCanvas: Canvas | null    // 当前编辑的画布
└── actions
    ├── loadAllCanvases()           // 从 localStorage 加载所有画布
    ├── createCanvas(name?)         // 创建画布,自动分配 UUID
    ├── deleteCanvas(id)
    ├── loadCanvas(id)              // structuredClone 深拷贝加载
    └── saveCanvas()                // 保存 currentCanvas 到 localStorage

flowStore (与 Vue Flow 集成)
├── nodes / edges                   // 来自 useVueFlow 的响应式引用
├── _syncing: boolean               // 防止双重触发同步的标志位
├── event listeners                 // onNodeDragStop/onMoveEnd/onEdgesChange/onNodesChange → syncToCanvas
└── actions
    ├── addNode(type, position)     // 创建节点 + 默认数据 + syncToCanvas
    ├── removeNode(id)              // 设置 _syncing + removeNodes + syncToCanvas
    ├── updateNodeData(id, data)    // 更新部分数据 + syncToCanvas
    ├── addEdge(edge)               // validateEdge → addEdges + syncToCanvas
    ├── removeEdge(id)              // 设置 _syncing + removeEdges + syncToCanvas
    ├── loadFromCanvas()            // canvasStore → setNodes/setEdges/setViewport
    ├── syncToCanvas()              // nodes/edges/viewport → canvasStore.saveCanvas()
    └── validateEdge(edge)          // 委托 flowValidation 纯函数校验

flowValidation (纯函数,无 store 依赖)
├── wouldCreateCycle(edges, source, target)  // BFS 环路检测
└── validateEdge(edges, newEdge)             // 自连接 → 循环 → 重复,返回 { valid, reason? }

AI 服务接口

已接入真实后端 API(见 ADR-004):

操作API Endpoint返回值
文本生成POST /ability/v1/texts/action/generatestring(生成文本)
图片生成POST /ability/v1/images/action/generatestring[](图片 URL 列表)
视频生成POST /ability/v1/videos/action/generatestring(视频 URL)
模型列表GET /resource/v1/modelsAiModelInfo[]

详见 AI Service 模块契约

modelsStore

modelsStore
├── cache: Partial<Record<ModelModality, AiModelInfo[]>>
├── loading: Partial<Record<ModelModality, boolean>>
├── errors: Partial<Record<ModelModality, string>>
└── actions
    ├── fetchModels(modality)          // 带缓存 + 防重复请求
    ├── getModels(modality)            // 返回 AiModelInfo[]
    ├── getAiModels(modality)          // 返回 AiModel[](简化视图)
    ├── getDefaultModelKey(modality)   // 返回第一个模型 name
    ├── isLoading(modality)
    └── getError(modality)