Skip to content

模型选择器组件设计文档

组件职责

  • 按上游分组展示 AI 模型,根据 category 参数过滤
  • 只暴露 v-model:aimodel-id,不暴露 upstream-id
  • 内部计算 upstreamId 用于分组显示
  • 自动选择首个可用模型(可禁用)
  • 通过 defineExpose 暴露完整的 Upstream 和 Aimodel 对象

API

Props

属性类型必填默认值说明
upstreamsUpstream[]-上游配置列表(含 aimodels 子表)
category'chat' | 'image' | 'video'-模型分类
aimodelIdnumber | nullnull选中的模型 ID(v-model)
readOnlybooleanfalse只读模式
dropdownWidthstring'w-80'下拉面板宽度
listLayoutbooleanfalse列表布局(否则 grid)
noAutoSelectbooleanfalse禁用自动选择
alignRightbooleanfalse下拉框右对齐

Emits

事件参数说明
update:aimodelIdid: number | null模型 ID 变化

Expose

属性类型说明
selectedUpstreamComputedRef<Upstream | undefined>当前选中的上游对象
selectedAimodelComputedRef<Aimodel | undefined>当前选中的模型对象

使用示例

基础用法

vue
<script setup lang="ts">
const { upstreams } = useUpstreams()
const selectedAimodelId = ref<number | null>(null)
</script>

<template>
  <ModelSelector
    :upstreams="upstreams"
    category="chat"
    v-model:aimodel-id="selectedAimodelId"
  />
</template>

获取完整对象

vue
<script setup lang="ts">
const { upstreams } = useUpstreams()
const selectedAimodelId = ref<number | null>(null)
const modelSelectorRef = ref()

// 通过 ref 获取完整对象
const selectedAimodel = computed(() => modelSelectorRef.value?.selectedAimodel)
const selectedUpstream = computed(() => modelSelectorRef.value?.selectedUpstream)

function handleSubmit() {
  if (!selectedAimodel.value) return

  // 使用完整对象的字段
  const data = {
    aimodelId: selectedAimodel.value.id,
    modelType: selectedAimodel.value.modelType,
    apiFormat: selectedAimodel.value.apiFormat,
    modelName: selectedAimodel.value.modelName,
  }
}
</script>

<template>
  <ModelSelector
    ref="modelSelectorRef"
    :upstreams="upstreams"
    category="image"
    v-model:aimodel-id="selectedAimodelId"
  />
</template>

重要说明

数据流向

  1. 父组件传入:只需传入 upstreamscategory
  2. 组件内部:根据 aimodelId 自动计算 upstreamId(用于分组显示)
  3. 对外暴露:只暴露 aimodelId,不暴露 upstreamId
typescript
// 组件内部计算 upstreamId(只用于显示)
const computedUpstreamId = computed(() => {
  if (!props.aimodelId) return null
  for (const upstream of props.upstreams) {
    if (upstream.aimodels?.some(m => m.id === props.aimodelId)) {
      return upstream.id
    }
  }
  return null
})

不要传递 upstreamId

错误用法

vue
<ModelSelector
  v-model:upstream-id="selectedUpstreamId"
  v-model:aimodel-id="selectedAimodelId"
/>

正确用法

vue
<ModelSelector
  v-model:aimodel-id="selectedAimodelId"
/>

获取完整对象的最佳实践

不推荐:手动查找

typescript
const selectedAimodel = computed(() => {
  const upstream = upstreams.value.find(u => u.id === upstreamId)
  return upstream?.aimodels.find(m => m.id === aimodelId)
})

推荐:通过 ref

typescript
const modelSelectorRef = ref()
const selectedAimodel = computed(() => modelSelectorRef.value?.selectedAimodel)

注意事项

  1. 必须包含子表:传入的 upstreams 必须通过 loadUpstreams() 加载,确保包含 aimodels 子表
  2. 单一数据源aimodel.upstreamId 是唯一来源,前端不需要维护 upstreamId 状态
  3. 自动选择:首次加载时自动选择第一个可用模型,除非设置 no-auto-select
  4. 空状态:无模型时自动显示提示信息,引导用户添加配置
  5. 布局选择:对话场景使用 grid,绘图/视频场景建议使用 list-layout

MJ-Studio - 多模型 AI 工作台