feat: Video 平台新增图生视频/全能参考/主体参考三种生成模式

- pattern 控件改为支持 Element Plus 图标组件,部分选项改用图标替代 SVG
- 新增 isStr 函数区分图标组件与 SVG 图片路径
- 智能多帧选项暂时标记为 disabled
- modelSelector 增加新模式→modelType 映射(imageToVideo/allReference/subjectReference)
- imageUploader 增加新模式标签文本(参考图/主体)
- 平台注册表 key 统一转为小写,支持大小写不敏感查找
- 更新 workflow 上传地址
This commit is contained in:
王佑琳 2026-06-12 16:07:36 +08:00
parent 45a80b83ff
commit 61867e4f59
8 changed files with 44 additions and 15 deletions

View File

@ -10,7 +10,7 @@ VITE_API_PAY_PREFIX = '/pay'
VITE_API_PAY_TARGET = 'http://test.xueai.art' # http://43.248.133.202 test.xueai.art VITE_API_PAY_TARGET = 'http://test.xueai.art' # http://43.248.133.202 test.xueai.art
# 任务处理模块 # 任务处理模块
VITE_API_WORKFLOW_UPLOAD = 'http://43.248.97.19:4000/aigc/workflow/file/upload' # https://sxwz.xueai.art/workflow https://designtools.xueai.art/workflow VITE_API_WORKFLOW_UPLOAD = 'http://test.xueai.art/AIGC/Temp/uploadImage' # https://sxwz.xueai.art/workflow https://designtools.xueai.art/workflow
VITE_API_TASK_PREFIX = '/suanli' VITE_API_TASK_PREFIX = '/suanli'
VITE_API_TASK_TARGET = 'http://test.xueai.art' VITE_API_TASK_TARGET = 'http://test.xueai.art'

View File

@ -0,0 +1 @@
输入框是否可以以当前宽度为最小值,当参数的选择框挤压发送按钮时输入框可以变宽

3
components.d.ts vendored
View File

@ -16,6 +16,7 @@ declare module 'vue' {
DialogBox: typeof import('./src/components/dialogBox/index.vue')['default'] DialogBox: typeof import('./src/components/dialogBox/index.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
IEpCalendar: typeof import('~icons/ep/calendar')['default'] IEpCalendar: typeof import('~icons/ep/calendar')['default']
@ -25,10 +26,12 @@ declare module 'vue' {
IEpPlus: typeof import('~icons/ep/plus')['default'] IEpPlus: typeof import('~icons/ep/plus')['default']
IEpStar: typeof import('~icons/ep/star')['default'] IEpStar: typeof import('~icons/ep/star')['default']
Img: typeof import('./src/components/Img/index.vue')['default'] Img: typeof import('./src/components/Img/index.vue')['default']
ParamGroup: typeof import('./src/components/ParamGroup/index.vue')['default']
Popover: typeof import('./src/components/Popover/index.vue')['default'] Popover: typeof import('./src/components/Popover/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
Select: typeof import('./src/components/Select/index.vue')['default'] Select: typeof import('./src/components/Select/index.vue')['default']
SwitchControl: typeof import('./src/components/SwitchControl/index.vue')['default']
VirtualScroller: typeof import('./src/components/virtual-scroller/VirtualScroller.vue')['default'] VirtualScroller: typeof import('./src/components/virtual-scroller/VirtualScroller.vue')['default']
'VirtualScroller copy': typeof import('./src/components/virtual-scroller/VirtualScroller copy.vue')['default'] 'VirtualScroller copy': typeof import('./src/components/virtual-scroller/VirtualScroller copy.vue')['default']
} }

View File

@ -1,8 +1,8 @@
import AutoImport from 'unplugin-auto-import/vite' import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver' import IconsResolver from 'unplugin-icons/resolver'
import Icons from 'unplugin-icons/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
export const autoImportConfig = AutoImport({ export const autoImportConfig = AutoImport({
imports: [ imports: [

View File

@ -1,17 +1,19 @@
/** 平台注册表id → definePlatform 工厂函数 */ /** 平台注册表id → definePlatform 工厂函数key 统一为小写) */
const registry = {} const registry = {}
/** 注册平台 */ /** 注册平台 */
export function registerPlatform(id, factory) { export function registerPlatform(id, factory) {
if (registry[id]) { const key = id.toLowerCase()
if (registry[key]) {
console.warn(`平台 "${id}" 已注册,将被覆盖`) console.warn(`平台 "${id}" 已注册,将被覆盖`)
} }
registry[id] = factory registry[key] = factory
} }
/** 根据平台类型创建平台实例 */ /** 根据平台类型创建平台实例 */
export function createPlatform(type) { export function createPlatform(type) {
const factory = registry[type] const key = type.toLowerCase()
const factory = registry[key]
if (!factory) throw new Error(`未注册的平台: ${type}`) if (!factory) throw new Error(`未注册的平台: ${type}`)
return factory() return factory()
} }

View File

@ -6,11 +6,13 @@
position="top" position="top"
> >
<template #prefix> <template #prefix>
<img :src="selectedIcon" alt="" style="width: 20px;"> <component v-if="!isStr(selectedIcon)" :is="selectedIcon" style="width: 20px;" />
<img v-else :src="selectedIcon" alt="" style="width: 20px;">
</template> </template>
<template #option="{ option }"> <template #option="{ option }">
<div class="option-content-custom"> <div class="option-content-custom">
<img :src="option.icon" alt="" style="width: 20px;"> <component v-if="!isStr(option.icon)" :is="option.icon" style="width: 20px;" />
<img v-else :src="option.icon" alt="" style="width: 20px;">
<span v-if="option.labelText" class="option-label-text">{{ option.labelText }}</span> <span v-if="option.labelText" class="option-label-text">{{ option.labelText }}</span>
</div> </div>
</template> </template>
@ -18,8 +20,8 @@
</template> </template>
<script setup> <script setup>
import { ChatLineSquare, Picture, VideoCamera } from '@element-plus/icons-vue'
import videoPattern2 from '@/assets/dialog/videoPattern2.svg' import videoPattern2 from '@/assets/dialog/videoPattern2.svg'
import videoPattern4 from '@/assets/dialog/videoPattern4.svg' import videoPattern4 from '@/assets/dialog/videoPattern4.svg'
import videoPattern5 from '@/assets/dialog/videoPattern5.svg' import videoPattern5 from '@/assets/dialog/videoPattern5.svg'
import videoPattern6 from '@/assets/dialog/videoPattern6.svg' import videoPattern6 from '@/assets/dialog/videoPattern6.svg'
@ -40,17 +42,20 @@ const quantity = computed({
}) })
const quantityOptions = [ const quantityOptions = [
{ value: '文生视频', label: '文生视频', labelText: '文生视频', icon: videoPattern2 }, { value: '文生视频', label: '文生视频', labelText: '文生视频', icon: markRaw(ChatLineSquare) },
{ value: '图生视频', label: '图生视频', labelText: '图生视频', icon: markRaw(Picture) },
{ value: '首尾帧', label: '首尾帧', labelText: '首尾帧', icon: videoPattern2 }, { value: '首尾帧', label: '首尾帧', labelText: '首尾帧', icon: videoPattern2 },
{ value: '数字人', label: '数字人', labelText: '数字人', icon: videoPattern2 }, { value: '数字人', label: '数字人', labelText: '数字人', icon: markRaw(VideoCamera) },
{ value: '全能参考', label: '全能参考', labelText: '全能参考', icon: videoPattern4 }, { value: '全能参考', label: '全能参考', labelText: '全能参考', icon: videoPattern4 },
{ value: '智能多帧', label: '智能多帧', labelText: '智能多帧', icon: videoPattern5 }, { value: '智能多帧', label: '智能多帧', labelText: '智能多帧', icon: videoPattern5, disabled: true },
{ value: '主体参考', label: '主体参考', labelText: '主体参考', icon: videoPattern6 } { value: '主体参考', label: '主体参考', labelText: '主体参考', icon: videoPattern6 }
] ]
const isStr = (v) => typeof v === 'string'
const selectedIcon = computed(() => { const selectedIcon = computed(() => {
const option = quantityOptions.find((opt) => opt.value === quantity.value) const option = quantityOptions.find((opt) => opt.value === quantity.value)
return option ? option.icon : videoPattern1 return option ? option.icon : videoPattern2
}) })
</script> </script>

View File

@ -76,6 +76,12 @@ const getFrameLabel = (index) => {
if (props.modelType === 'digitalHuman') { if (props.modelType === 'digitalHuman') {
return '' return ''
} }
if (props.modelType === 'imageToVideo' || props.modelType === 'allReference') {
return '参考图'
}
if (props.modelType === 'subjectReference') {
return '主体'
}
return index === 0 ? '首帧' : '尾帧' return index === 0 ? '首帧' : '尾帧'
} }
@ -83,6 +89,12 @@ const getUploadText = (i) => {
if (props.modelType === 'digitalHuman') { if (props.modelType === 'digitalHuman') {
return '参考内容' return '参考内容'
} }
if (props.modelType === 'imageToVideo' || props.modelType === 'allReference') {
return '参考图'
}
if (props.modelType === 'subjectReference') {
return '主体'
}
return i === 1 ? '首帧' : '尾帧' return i === 1 ? '首帧' : '尾帧'
} }

View File

@ -80,10 +80,16 @@ const getModelType = (value) => {
switch (value) { switch (value) {
case '文生视频': case '文生视频':
return 'text' return 'text'
case '图生视频':
return 'imageToVideo'
case '首尾帧': case '首尾帧':
return 'image' return 'image'
case '数字人': case '数字人':
return 'digitalHuman' return 'digitalHuman'
case '全能参考':
return 'allReference'
case '主体参考':
return 'subjectReference'
default: default:
return 'text' return 'text'
} }