AI_Painting_V2.0/docs/superpowers/specs/2026-06-09-platform-architecture-design.md

6.7 KiB
Raw Blame History

平台化架构设计

目标

将 Painting / Video 两套硬编码分支重构为统一的平台描述符架构,使加入新平台只需新建一个文件夹并实现标准接口,零改动 dialogBox。

背景

当前 dialogBox/index.vue792 行)通过 v-if="type === 'Painting'" / v-if="type === 'Video'" 承载两套完全不同的逻辑:

  • 模型列表Painting 走后端 APIVideo 走静态 JSON
  • 参数 schemaPainting 走本地 JS 文件Video 走远程 workflow JSON
  • UI 控件Painting 有 proportion/dimension/quality/quantityVideo 有 pattern/proportion/time
  • 任务 bodyPainting 扁平 modelParamsVideo { workflowId, nodeInfoList }

后续模型参数后端化后,所有平台将统一为"API 获取模型列表 + API 获取参数 schema"模式。

核心设计:平台描述符模式

每个平台封装为一个文件夹,导出 definePlatform() 工厂函数返回标准接口对象。dialogBox 退化为纯渲染引擎。

平台接口

// src/platforms/<name>/index.js
export function definePlatform() {
  // 响应式状态(各平台自定义)
  const model = ref(defaultValue)
  const modelType = ref(defaultValue)
  const state = reactive({ ... })

  // 模型选择器组件
  const ModelSelector = markRaw(Component)

  // 参数控件列表(有序,决定渲染顺序)
  const controls = [
    {
      name: 'proportion',
      component: markRaw(ProportionComponent),
      show: (config) => config?.params?.some(p => p.ui === 'proportion'),
      props: (config) => ({ /* 额外 props */ }),
    },
    // ...
  ]

  // 图片上传器(可选)
  const ImageUploader = markRaw(Component) | null

  return {
    id: 'painting',            // 平台标识
    label: 'AI绘画2026',        // 显示标题
    ModelSelector,              // 模型选择器组件
    controls,                   // 有序控件列表
    ImageUploader,              // 图片上传器组件(可选)
    state,                      // 平台自定义响应式状态
    model,                      // 当前模型 ref
    modelType,                  // 当前模型类型 ref

    async loadModels() { },           // 获取模型列表
    async loadConfig(modelName) { },  // 获取模型参数配置
    buildTaskBody(state) { },         // 构造请求 body
    getDefaultModel() { },            // 默认模型名称
    isImageRequired(state) { },       // 是否必须上传图片
  }
}

控件绑定约定

dialogBox 渲染控件时自动处理 namestate 的 v-model 绑定:

  • modelValuestate[name]
  • onUpdate:modelValuestate[name] = v

控件 descriptor 仅需定义 show 条件(基于 modelConfig 上下文)和额外 props

平台注册表

// src/platforms/registry.js
import { definePaintingPlatform } from './painting/index.js'
import { defineVideoPlatform } from './video/index.js'

const registry = { Painting, Video }

export function createPlatform(type) {
  const factory = registry[type]
  if (!factory) throw new Error(`未找到平台: ${type}`)
  return factory()
}

dialogBox 角色变化

dialogBox 接收 type prop → 调用 createPlatform(type) → 获得 descriptor → 据 descriptor 渲染一切:

  1. 渲染 <component :is="platform.ModelSelector">
  2. 遍历 platform.controlsshow 返回 true 的渲染 <component :is>
  3. handleStart() 委托给 platform.buildTaskBody(state) → 调用 taskPolling.generate(body)
  4. watch(model) 委托给 platform.loadConfig(name)

数据流

flowchart TD
    subgraph dialogBox["dialogBox 编排层"]
        A["platform.loadModels()"] --> B[模型选择器渲染]
        B --> C["watch(model) → platform.loadConfig(name)"]
        C --> D[计算 visibleControls]
        D --> E["v-for 渲染 controls自动 v-model"]
        E --> F["handleStart → platform.buildTaskBody()"]
        F --> G["taskPolling.generate(body)"]
    end

    subgraph platform["platform 包"]
        H["loadModels() → API"]
        I["loadConfig(name) → API"]
        J["buildTaskBody() → 扁平 body"]
    end

    G --> K[POST /suanli/v1/tasks]
    K --> L[轮询 → displayStore 更新虚拟滚动列表]

目录结构

src/
├── platforms/                          # 平台包(新增)
│   ├── painting/
│   │   ├── index.js                    # definePlatform()
│   │   ├── modelSelector.vue
│   │   ├── imageUploader.vue
│   │   └── controls/
│   │       ├── proportion.vue
│   │       ├── dimension.vue
│   │       ├── quality.vue
│   │       └── quantity.vue
│   ├── video/
│   │   ├── index.js
│   │   ├── modelSelector.vue
│   │   ├── imageUploader.vue
│   │   └── controls/
│   │       ├── pattern.vue
│   │       ├── proportion.vue
│   │       └── time.vue
│   └── registry.js
│
├── components/
│   ├── dialogBox/index.vue             # 精简后 ~200 行
│   ├── Popover/                        # 共享基础组件(不变)
│   ├── Select/                         # 共享基础组件(不变)
│   ├── Img/                            # 共享基础组件(不变)
│   └── virtual-scroller/               # 共享基础组件(不变)
│
├── apis/                               # API 层(不变)
├── utils/
│   ├── taskPolling.js                   # 任务轮询(不变)
│   ├── request.js                       # Axios不变
│   └── modelApi.js                      # 平台 API 封装
│
├── config/
│   ├── models/                          # 逐步废弃
│   ├── runninghub/                      # 逐步废弃
│   └── plugins.js                       # 不变

迁移路径

步骤 内容 影响范围
1 新建 src/platforms/ + registry.js,不删旧代码 纯新增
2 Painting 迁入 descriptordialogBox 切换读取路径 dialogBox 精简
3 Video 迁入 descriptor dialogBox 继续精简
4 删除旧代码:config/models/config/runninghub/modelConfig.js 清理
5 后端化:各平台 loadConfig() 改为调 API 仅改 descriptor 内部

每步独立提交,方便回滚。

不变更的部分

  • taskPolling.js:任务创建和轮询逻辑通用,不变
  • displayStore:虚拟滚动列表状态通用,不变
  • PopoverSelectImgvirtual-scroller:共享 UI 组件
  • home/index.vue:仍然传 type prop不变
  • apis/request.jsHTTP 层不变
  • config/plugins.js、router、stores不变