Skip to content

模块:State Management

唯一职责:管理全局应用状态(画布列表、画布编辑状态、模型缓存),持久化到 localStorage。

边界

属于本模块:

  • 画布列表的 CRUD(canvasStore)
  • 画布数据的 localStorage 持久化
  • Vue Flow 节点/边的状态管理和持久化同步(flowStore)
  • 连线校验纯函数(flowValidation)
  • 模型列表的异步获取与缓存(modelsStore)

不属于本模块:

  • Vue Flow 实例的渲染和交互事件(由 Vue Flow 库 + Canvas Editor 负责)
  • AI API 的 HTTP 调用(由 AI Service 负责)
  • 组件级局部状态

对外接口

canvasStore

ts
interface CanvasStoreAPI {
  // 状态
  canvases: Ref<Canvas[]>
  currentCanvas: Ref<Canvas | null>

  // 方法
  loadAllCanvases: () => void // 从 localStorage 加载
  createCanvas: (name?: string) => Canvas // 创建并持久化
  deleteCanvas: (id: string) => void // 删除并持久化
  loadCanvas: (id: string) => Canvas | null // 加载到 currentCanvas
  renameCanvas: (id: string, name: string) => void
  saveCanvas: () => void // 持久化 currentCanvas
}

flowStore

ts
interface FlowStoreAPI {
  // 状态(只读)
  nodes: Readonly<Ref<Node[]>>
  edges: Readonly<Ref<Edge[]>>

  // 方法
  addNode: (type: NodeType, position: { x: number, y: number }) => Node
  removeNode: (id: string) => void
  updateNodeData: (id: string, data: Partial<CanvasNode['data']>) => void
  addEdge: (edge: Omit<CanvasEdge, 'id'>) => CanvasEdge | null // null = 验证失败
  addBatchEdges: (memberIds: string[], targetNodeId: string, handleType: HandleType) => CanvasEdge[] // 批量创建,逐条验证,单次 sync
  removeEdge: (id: string) => void
  loadFromCanvas: () => void // 从 currentCanvas 加载到 Vue Flow
  syncToCanvas: () => void // Vue Flow → currentCanvas → localStorage
  validateEdge: (newEdge: Omit<CanvasEdge, 'id'>) => EdgeValidationResult
}

modelsStore

ts
interface ModelsStoreAPI {
  fetchModels: (modality: ModelModality) => Promise<void> // 带缓存
  getModels: (modality: ModelModality) => AiModelInfo[]
  getAiModels: (modality: ModelModality) => AiModel[] // 简化视图
  getDefaultModelKey: (modality: ModelModality) => string | undefined
  isLoading: (modality: ModelModality) => boolean
  getError: (modality: ModelModality) => string | undefined
}

flowValidation(纯函数)

typescript
function validateEdge(edges, newEdge): EdgeValidationResult
function wouldCreateCycle(edges, source, target): boolean

interface EdgeValidationResult {
  valid: boolean
  reason?: 'self-connection' | 'cycle' | 'duplicate' | 'invalid-handle-direction' | 'uploaded-target'
}

状态同步流

用户操作 → Vue Flow 内部状态变更
                  ↓ (onNodeDragStop / onMoveEnd / onEdgesChange)
           flowStore.syncToCanvas()

        canvasStore.currentCanvas 更新

        canvasStore.saveCanvas()

          localStorage 写入

不变量

  1. canvasStore.canvases 与 localStorage 始终同步(每次写操作后立即 persistAll
  2. flowStore.addEdge / addBatchEdges 在添加前必须通过 validateEdge,验证失败返回 null / 跳过
  3. syncToCanvas 过滤 group node(type === 'group')和关联边,不持久化到 localStorage
  4. modelsStore.fetchModels 对同一 modality 不重复请求(缓存 + loading 防重)
  5. 节点 ID 在同一 Canvas 内唯一(由 crypto.randomUUID() 保证)

错误场景

场景模块行为调用方职责
localStorage 读取时 JSON.parse 失败(数据损坏)返回空数据(空画布列表/空节点),不抛异常页面展示空状态或错误提示
localStorage 写入时配额已满(QuotaExceededError)saveCanvas() / persistAll() 抛出异常调用方捕获异常并提示用户
loadCanvas(id) 传入不存在的 id返回 nullcurrentCanvas 不变Canvas Editor 显示错误页面
fetchModels() 网络请求失败getError(modality) 返回错误信息,isLoading 恢复为 false消费方读取 getError 展示提示
syncToCanvas()currentCanvasnull 时调用静默忽略,不执行同步无需处理
多标签页并发修改同一画布不做冲突检测,后写入的覆盖先写入的(last-write-wins)当前不支持协作,无需处理

实现位置

角色文件路径
canvasStoreapps/web/stores/canvasStore.ts
flowStoreapps/web/stores/flowStore.ts
modelsStoreapps/web/stores/modelsStore.ts
flowValidationapps/web/stores/flowValidation.ts
测试apps/web/test/unit/flowValidation.test.ts
测试apps/web/test/nuxt/flowStore.test.ts
测试apps/web/test/nuxt/canvasStore.test.ts