refactor: dialogBox 重构为通用平台编排壳,委托所有平台特定逻辑

This commit is contained in:
王佑琳 2026-06-09 11:51:29 +08:00
parent 615afbc211
commit ec81dce28a
2 changed files with 129 additions and 533 deletions

View File

@ -1,80 +1,49 @@
<template> <template>
<Transition name="slide-up"> <Transition name="slide-up">
<div class="input-container" :class="{ generate : !props.isGenerate }" @click="handleContainerClick"> <div class="input-container" :class="{ generate : !props.isGenerate }" @click="handleContainerClick">
<div v-if="!props.isGenerate && props.type === 'Painting'" class="title">AI绘画2026</div> <div v-if="!props.isGenerate" class="title">{{ platform.label }}</div>
<div v-if="!props.isGenerate && props.type === 'Video'" class="title">AI视频2026</div>
<div class="sender-top"> <div class="sender-top">
<div v-if="useDisplay.Sender_variant === 'default'" class="scroll-to-bottom-text" @click.stop="handleScrollToBottom">回到底部<img src="@/assets/dialog/ArrowDown.svg"></div> <div v-if="useDisplay.Sender_variant === 'default'" class="scroll-to-bottom-text" @click.stop="handleScrollToBottom">
回到底部<img src="@/assets/dialog/ArrowDown.svg">
</div>
<div v-show="showImageUploader" class="upload-img-container"> <div v-show="showUploader" class="upload-img-container">
<div class="reference-diagram"> <div class="reference-diagram">
<ImageUploader <component
v-if="props.type === 'Painting'" v-if="platform.ImageUploader"
:is="platform.ImageUploader"
ref="referenceDiagramRef" ref="referenceDiagramRef"
v-model="referenceImages" v-model="referenceImages"
:limit="imageUploadLimit" v-bind="uploaderBindings"
@open-canvas="handleOpenCanvas"
/>
<VideoImageUploader
v-else-if="props.type === 'Video'"
ref="referenceDiagramRef"
v-model="referenceImages"
:model-type="modelType"
:images-count="modelDisplayConfig?.display?.images || 1"
/> />
</div> </div>
</div> </div>
</div> </div>
<Sender :key="useDisplay.Sender_variant" v-model="prompt" :variant="useDisplay.Sender_variant" :placeholder="promptPlaceholder" :submit-btn-disabled="isgerenate.value" :auto-size="autoSizeConfig"> <Sender
<template #prefix> v-model="prompt"
<div v-if="useDisplay.Sender_variant !== 'default' && props.type === 'Painting'" class="prefix-self-wrap"> :variant="useDisplay.Sender_variant"
<paintingModel v-model="model" v-model:typeValue="modelType" /> :placeholder="platform.promptPlaceholder.value"
<paintingProportion :submit-btn-disabled="isgerenate"
v-if="showProportion" :auto-size="autoSizeConfig"
v-model="proportion"
v-model:resolution="resolution"
v-model:width="customWidth"
v-model:height="customHight"
:proportion-options="paintingProportionOpts"
:resolution-options="paintingResolutionOpts"
:allow-custom="hasCustomSize"
/>
<DimensionInput
v-if="showDimension"
v-model:width="dimWidth"
v-model:height="dimHeight"
:min-w="dimMinW"
:max-w="dimMaxW"
:min-h="dimMinH"
:max-h="dimMaxH"
/>
<Select
v-if="showQuality"
v-model="qualityValue"
:options="qualityOpts"
width="auto"
class="quality-select"
> >
<template #prefix> <template v-if="useDisplay.Sender_variant !== 'default'" #prefix>
<span class="quality-label">画质</span> <div class="prefix-self-wrap">
</template> <component
</Select> :is="platform.ModelSelector"
<Quantity v-if="showQuantity" v-model="quantity" :max="quantityMax" /> :modelValue="platform.model.value"
</div> @update:modelValue="platform.model.value = $event"
:typeValue="platform.modelType.value"
<div v-if="useDisplay.Sender_variant !== 'default' && props.type === 'Video'" class="prefix-self-wrap"> @update:typeValue="platform.modelType.value = $event"
<Pattern v-model="videoPattern" /> v-bind="(platform.modelSelectorProps && platform.modelSelectorProps()) || {}"
<videoModel v-model="model" v-model:typeValue="modelType" :video-pattern="videoPattern" />
<videoProportion
v-model="proportion"
v-model:resolution="resolution"
:proportion-options="proportionOptions"
:resolution-options="resolutionOptions"
/> />
<Time v-model="duration" :options="durationOptions" /> <template v-for="ctrl in visibleControls" :key="ctrl.name">
<component
:is="ctrl.component"
v-bind="ctrl.props(getCurrentConfig())"
/>
</template>
</div> </div>
</template> </template>
@ -84,8 +53,8 @@
<i-ep-loading style="animation: spin 1s linear infinite;" /> <i-ep-loading style="animation: spin 1s linear infinite;" />
</el-button> </el-button>
<div v-else class="gerenate" :class="{ isprompt: prompt }" @click="handleStart"> <div v-else class="gerenate" :class="{ isprompt: prompt }" @click="handleStart">
<img v-if="!prompt" src="@/assets/dialog/darkArrow.svg" alt="" /> <img v-if="!prompt" src="@/assets/dialog/darkArrow.svg" alt="">
<img v-else src="@/assets/dialog/writerArrow.svg" alt="" /> <img v-else src="@/assets/dialog/writerArrow.svg" alt="">
<div v-show="useDisplay.Sender_variant !== 'default'">发送</div> <div v-show="useDisplay.Sender_variant !== 'default'">发送</div>
</div> </div>
</div> </div>
@ -97,415 +66,117 @@
</template> </template>
<script setup> <script setup>
import videoProportion from './proportion/video.vue'
import paintingModel from './model/painting.vue'
import videoModel from './model/video.vue'
import Pattern from './pattern/index.vue'
import ImageUploader from './imageUploader/index.vue'
import VideoImageUploader from './videoImageUploader/index.vue'
import Time from './Time/index.vue'
import paintingProportion from './proportion/painting.vue'
import Quantity from './quantity/index.vue'
import DimensionInput from './dimension/index.vue'
import Select from '@/components/Select/index.vue'
import { Sender } from 'vue-element-plus-x' import { Sender } from 'vue-element-plus-x'
import { useDisplayStore } from '@/stores' import { useDisplayStore } from '@/stores'
import { generate } from '@/utils/taskPolling' import { generate } from '@/utils/taskPolling'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { getModelId, fetchPlatformModels, getPlatformCode } from '@/utils/modelApi' import { createPlatform } from '@/platforms/registry.js'
import { fetchModelConfig } from '@/utils/modelConfig' import { getModelId } from '@/utils/modelApi'
import { getModelConfig } from '@/config/models/index.js'
//
import '@/platforms/painting/index.js'
import '@/platforms/video/index.js'
const props = defineProps({ const props = defineProps({
isGenerate: { isGenerate: { type: Boolean, default: false },
type: Boolean, generate: { type: Boolean, default: false },
default: false type: { type: String, default: 'Painting' },
},
generate: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'Painting'
}
}) })
const router = useRouter() const router = useRouter()
const useDisplay = useDisplayStore() const useDisplay = useDisplayStore()
const isgerenate = ref(false) const isgerenate = ref(false)
const prompt = ref('')
const model = ref() //
const modelType = ref('text')
//
const modelConfig = computed(() => {
return props.type === 'Painting' ? getModelConfig(model.value) : null
})
//
const paramValues = reactive({})
const showImageUploader = computed(() => {
if (props.type === 'Video') return modelType.value !== 'text'
return modelType.value !== 'text' || modelConfig.value?.inputType === 'image' || modelConfig.value?.inputType === 'both'
})
// imageNum
const showQuantity = computed(() => {
if (props.type !== 'Painting') return false
return !!modelConfig.value?.params?.find(p => p.ui === 'quantity')
})
// 使 proportion aspectRatio
const showProportion = computed(() => {
return !!modelConfig.value?.params?.find(p => p.ui === 'proportion')
})
// aspectRatio 'custom'
const hasCustomSize = computed(() => {
const ratioParam = modelConfig.value?.params?.find(p => p.ui === 'proportion')
return ratioParam?.options?.includes('custom') || false
})
// DimensionInput
const dimWidth = ref(1024)
const dimHeight = ref(1024)
const qualityValue = ref('medium')
const showDimension = computed(() => {
return !!modelConfig.value?.params?.find(p => p.ui === 'dimension' || p.ui === 'dimensionWidth')
})
const dimConfig = computed(() => {
if (!modelConfig.value) return null
const dimParam = modelConfig.value.params.find(p => p.ui === 'dimension')
if (dimParam) return { type: 'combined', config: dimParam.dimension, paramName: dimParam.name }
const wParam = modelConfig.value.params.find(p => p.ui === 'dimensionWidth')
const hParam = modelConfig.value.params.find(p => p.ui === 'dimensionHeight')
if (wParam && hParam) return { type: 'split', wParam, hParam }
return null
})
const dimMinW = computed(() => dimConfig.value?.config?.width?.min || dimConfig.value?.wParam?.min || 256)
const dimMaxW = computed(() => dimConfig.value?.config?.width?.max || dimConfig.value?.wParam?.max || 6197)
const dimMinH = computed(() => dimConfig.value?.config?.height?.min || dimConfig.value?.hParam?.min || 256)
const dimMaxH = computed(() => dimConfig.value?.config?.height?.max || dimConfig.value?.hParam?.max || 4096)
const showQuality = computed(() => {
return !!modelConfig.value?.params?.find(p => p.name === 'quality')
})
const qualityOpts = computed(() => {
const q = modelConfig.value?.params?.find(p => p.name === 'quality')
if (q?.options) return q.options.map(o => ({ value: o, label: o }))
return []
})
// 退
const paintingProportionOpts = computed(() => {
const ratioParam = modelConfig.value?.params?.find(p => p.ui === 'proportion')
if (ratioParam?.options) {
return ratioParam.options
.filter(o => o !== 'custom')
.map(o => ({ value: o, label: o }))
}
return proportionOptions.value
})
// resolution
const paintingResolutionOpts = computed(() => {
const resParam = modelConfig.value?.params?.find(p => p.ui === 'resolution')
if (resParam?.options) {
return resParam.options.map(o => ({ value: o, label: o.toUpperCase() }))
}
return []
})
const imageUploadLimit = computed(() => {
if (!modelConfig.value) return 4
const imageParam = modelConfig.value.params.find(p => p.ui === 'imageUpload')
return imageParam?.maxCount || modelConfig.value.maxImages || 4
})
const promptPlaceholder = ref('描述你想生成的画面和动作。') //
const prompt = ref('') //
const proportion = ref('16:9') // Video
const resolution = ref('1k') // Video
const referenceImages = ref([]) const referenceImages = ref([])
// const platform = computed(() => createPlatform(props.type))
const quantity = ref(1) //
const customWidth = ref(1024) //
const customHight = ref(1024) //
const quantityMax = computed(() => { const getCurrentConfig = () => {
const qtyParam = modelConfig.value?.params?.find(p => p.ui === 'quantity') return platform.value.modelConfig?.value ?? platform.value.modelDisplayConfig?.value ?? null
if (qtyParam?.options?.length) return Math.max(...qtyParam.options) }
return 4
const visibleControls = computed(() => {
const config = getCurrentConfig()
return platform.value.controls.filter(c => c.show(config))
}) })
// paramValues UI refs const showUploader = computed(() => {
watch(modelConfig, (config) => { return platform.value.showImageUploader()
if (!config) return
config.params.forEach(p => {
if (!(p.name in paramValues)) {
if (p.name === 'outputFormat') {
paramValues[p.name] = 'png'
} else {
paramValues[p.name] = p.default ?? ''
}
}
})
// UI
const ratioParam = config.params.find(p => p.ui === 'proportion')
if (ratioParam) proportion.value = ratioParam.default || '1:1'
const resParam = config.params.find(p => p.ui === 'resolution')
if (resParam) resolution.value = resParam.default || '2k'
const qtyParam = config.params.find(p => p.ui === 'quantity')
if (qtyParam) quantity.value = qtyParam.default || 1
const cwParam = config.params.find(p => p.name === 'customWidth')
if (cwParam) customWidth.value = cwParam.default || 1024
const chParam = config.params.find(p => p.name === 'customHight')
if (chParam) customHight.value = chParam.default || 1024
// dimension quality
const qualityParam = config.params.find(p => p.name === 'quality')
if (qualityParam) qualityValue.value = qualityParam.default || 'medium'
const dc = dimConfig.value
if (dc?.type === 'split') {
dimWidth.value = dc.wParam.default || 1024
dimHeight.value = dc.hParam.default || 1024
} else if (dc?.type === 'combined') {
const raw = paramValues[dc.paramName] || config.params.find(p => p.name === dc.paramName)?.default || ''
const parsed = dc.config.parse(raw)
dimWidth.value = parsed.width
dimHeight.value = parsed.height
}
}, { immediate: true })
// UI refs paramValues
watch(proportion, (val) => {
const p = modelConfig.value?.params?.find(param => param.ui === 'proportion')
if (p) paramValues[p.name] = val
})
watch(resolution, (val) => {
const p = modelConfig.value?.params?.find(param => param.ui === 'resolution')
if (p) paramValues[p.name] = val
})
watch(quantity, (val) => {
const p = modelConfig.value?.params?.find(param => param.ui === 'quantity')
if (p) paramValues[p.name] = val
})
watch(customWidth, (val) => {
if (modelConfig.value?.params?.find(p => p.name === 'customWidth')) {
paramValues.customWidth = val
}
})
watch(customHight, (val) => {
if (modelConfig.value?.params?.find(p => p.name === 'customHight')) {
paramValues.customHight = val
}
})
watch([dimWidth, dimHeight], ([w, h]) => {
const dc = dimConfig.value
if (!dc) return
if (dc.type === 'split') {
paramValues[dc.wParam.name] = w
paramValues[dc.hParam.name] = h
} else if (dc.type === 'combined') {
paramValues[dc.paramName] = dc.config.format(w, h)
}
})
watch(qualityValue, (val) => {
if (modelConfig.value?.params?.find(p => p.name === 'quality')) {
paramValues.quality = val
}
}) })
// paramValues const uploaderBindings = computed(() => {
watch(referenceImages, (imgs) => { const p = platform.value
const imageParam = modelConfig.value?.params?.find(p => p.ui === 'imageUpload') if (p.id === 'painting') {
if (imageParam) { return { limit: p.imageUploadLimit() }
paramValues[imageParam.name] = imgs.map(img => img.url)
} }
}, { deep: true }) if (p.id === 'video') {
return { modelType: p.modelType.value, imagesCount: p.imageUploadLimit() }
// }
const duration = ref(5) // return {}
const videoPattern = ref('文生视频') // '' })
const resolutionOptions = ref([
{ value: '1k', label: '标清 1K' },
{ value: '2k', label: '高清 2K' },
{ value: '4k', label: '超清 4K' },
])
const proportionOptions = ref([
{ value: '智能', label: '智能' },
{ value: '21:9', label: '21:9' },
{ value: '16:9', label: '16:9' },
{ value: '4:3', label: '4:3' },
{ value: '1:1', label: '1:1' },
{ value: '3:4', label: '3:4' },
{ value: '9:16', label: '9:16' },
])
const durationOptions = ref([])
const isInitialized = ref(false)
const autoSizeConfig = computed(() => { const autoSizeConfig = computed(() => {
if (useDisplay.Sender_variant !== 'default') { if (useDisplay.Sender_variant !== 'default') {
return { minRows: 5, maxRows: 9 } return { minRows: 5, maxRows: 9 }
} else {
return { minRows: 1, maxRows: 1 }
} }
return { minRows: 1, maxRows: 1 }
}) })
const modelDisplayConfig = ref(null)
// Video: workflow
const loadVideoModelConfig = async (modelName, currentModelType) => {
try {
const config = await fetchModelConfig(props.type, modelName, currentModelType)
modelDisplayConfig.value = config
if (config.display) {
const display = config.display
if (display.promptPlaceholder) {
promptPlaceholder.value = display.promptPlaceholder.default || '描述你想生成的画面和动作。'
}
if (display.prompt && !isInitialized.value) {
prompt.value = display.prompt.default || ''
}
if (display.resolution) {
resolution.value = display.resolution.default || '1k'
resolutionOptions.value = display.resolution.options || []
}
if (display.proportion) {
proportion.value = display.proportion.default || '16:9'
proportionOptions.value = display.proportion.options || []
}
if (display.duration) {
duration.value = display.duration.default || 5
durationOptions.value = display.duration.options || []
}
}
isInitialized.value = true
} catch (error) {
console.error('加载视频模型配置失败:', error)
}
}
const handleStart = async () => { const handleStart = async () => {
const currentType = props.type const p = platform.value
let currentModelType = modelType.value
if(model.value === 'Seedance 2.0') { if (props.type === 'Video' && p.model.value === 'Seedance 2.0') {
ElMessage.primary('敬请期待 Seedance 2.0') ElMessage.primary('敬请期待 Seedance 2.0')
return return
} }
if (!props.isGenerate) { if (!props.isGenerate) {
router.push({ name: 'home', query: { loading: false, Generate: true, type: currentType } }) router.push({ name: 'home', query: { loading: false, Generate: true, type: props.type } })
} }
if (!prompt.value) { if (!prompt.value) {
// eslint-disable-next-line no-undef
ElMessage.error('请输入提示词') ElMessage.error('请输入提示词')
return return
} }
if (showImageUploader.value && !referenceImages.value.length){ if (showUploader.value && p.isImageRequired() && !referenceImages.value.length) {
ElMessage.warning('请上传图片') ElMessage.warning('请上传图片')
return return
} }
isgerenate.value = true isgerenate.value = true
console.log('生成开始', isgerenate.value)
const imgs = []
referenceImages.value.forEach((img, index) => {
imgs.push({ name: `image_${index + 1}`, url: img.url })
})
// Painting const modelId = await getModelId(props.type, p.model.value)
const modelParams = { ...paramValues }
if (prompt.value) modelParams.prompt = prompt.value // modelParams
const body = await p.buildTaskBody({ prompt, referenceImages })
const generateData = { const generateData = {
model: model.value, model: p.model.value,
modelType: currentModelType, modelType: p.modelType.value,
prompt: prompt.value, prompt: prompt.value,
proportion: proportion.value,
referenceImages: referenceImages.value, referenceImages: referenceImages.value,
quantity: quantity.value, modelParams: body,
resolution: resolution.value,
customWidth: customWidth.value,
customHight: customHight.value,
duration: duration.value,
videoPattern: videoPattern.value,
modelParams,
} }
const modelId = await getModelId(currentType, model.value)
// Painting Video params
const isPainting = currentType === 'Painting'
const data = { const data = {
type: currentType, type: props.type,
modelType: currentModelType, modelType: p.modelType.value,
AIGC: currentType, modelName: p.model.value,
platform: 'runninghub',
modelName: model.value,
modelId: modelId || '', modelId: modelId || '',
modelParams: isPainting ? modelParams : {}, body,
params: isPainting ? [] : [ request: JSON.stringify(generateData),
{ name: 'prompt', data: prompt.value },
{ name: 'quantity', data: quantity.value },
{ name: 'proportion', data: proportion.value },
{ name: 'resolution', data: resolution.value },
{ name: 'duration', data: duration.value },
],
imgs,
request: JSON.stringify(generateData)
} }
await generate(data, generateData) await generate(data, generateData)
console.log('生成中', isgerenate.value)
} }
const fillParamsFromResult = (resultData) => { const fillParamsFromResult = (resultData) => {
if (!resultData) return if (!resultData) return
platform.value.fillFromResult(resultData)
if (resultData.model !== undefined) model.value = resultData.model
if (resultData.modelType !== undefined) modelType.value = resultData.modelType
if (resultData.prompt !== undefined) prompt.value = resultData.prompt if (resultData.prompt !== undefined) prompt.value = resultData.prompt
if (resultData.proportion !== undefined) proportion.value = resultData.proportion
if (resultData.referenceImages !== undefined) referenceImages.value = resultData.referenceImages if (resultData.referenceImages !== undefined) referenceImages.value = resultData.referenceImages
if (resultData.quantity !== undefined) quantity.value = resultData.quantity
if (resultData.resolution !== undefined) resolution.value = resultData.resolution
if (resultData.customWidth !== undefined) customWidth.value = resultData.customWidth
if (resultData.customHight !== undefined) customHight.value = resultData.customHight
if (resultData.duration !== undefined) duration.value = resultData.duration
if (resultData.videoPattern !== undefined) videoPattern.value = resultData.videoPattern
if (resultData.modelParams !== undefined) Object.assign(paramValues, resultData.modelParams)
// modelParams dimension/quality UI refs
nextTick(() => {
const dc = dimConfig.value
if (dc?.type === 'split') {
if (paramValues[dc.wParam.name] !== undefined) dimWidth.value = paramValues[dc.wParam.name]
if (paramValues[dc.hParam.name] !== undefined) dimHeight.value = paramValues[dc.hParam.name]
} else if (dc?.type === 'combined') {
if (paramValues[dc.paramName]) {
const parsed = dc.config.parse(paramValues[dc.paramName])
dimWidth.value = parsed.width
dimHeight.value = parsed.height
}
}
if (paramValues.quality !== undefined) qualityValue.value = paramValues.quality
})
} }
defineExpose({ defineExpose({ fillParamsFromResult, handleStart })
fillParamsFromResult,
handleStart
})
const handleContainerClick = () => { const handleContainerClick = () => {
if (useDisplay.Sender_variant === 'default') { if (useDisplay.Sender_variant === 'default') {
@ -514,46 +185,33 @@ const handleContainerClick = () => {
} }
const handleScrollToBottom = () => { const handleScrollToBottom = () => {
console.log('点击回到底部按钮')
useDisplay.scrollToBottom() useDisplay.scrollToBottom()
} }
const handleOpenCanvas = (data) => { watch(() => useDisplay.isSubGerenate, (v) => { isgerenate.value = v }, { immediate: true })
useDisplay.openCanvas(data)
}
watch(() => useDisplay.isSubGerenate, (newValue) => { //
console.log('生成状态', newValue) watch(
isgerenate.value = newValue [() => platform.value.model.value, () => platform.value.modelType.value],
}, { immediate: true }) async ([newModel, newModelType]) => {
watch([() => model.value, () => modelType.value], async ([newModel, newModelType]) => {
console.log('模型或类型改变:', newModel, newModelType)
if (!newModel) return if (!newModel) return
if (props.type !== 'Painting') { if (platform.value.id === 'video') {
await loadVideoModelConfig(newModel, newModelType) await platform.value.loadConfig(newModel, newModelType)
}
})
// ""
const prefetchModels = () => {
const code = getPlatformCode(props.type)
fetchPlatformModels(code)
}
watch(() => props.type, (newType) => {
if (newType === 'Video') {
model.value = 'LTX2.0'
} else { } else {
model.value = 'flux' platform.value.loadConfig(newModel)
} }
prefetchModels() },
}, { immediate: true }) )
// +
watch(() => props.type, (newType) => {
const p = createPlatform(newType)
p.model.value = p.getDefaultModel()
p.loadModels()
}, { immediate: true })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
/* 输入区域 */
.input-container { .input-container {
width: 50%; width: 50%;
max-width: 880px; max-width: 880px;
@ -591,20 +249,14 @@ watch(() => props.type, (newType) => {
justify-content: center; justify-content: center;
gap: 5px; gap: 5px;
&:active { &:active { transform: scale(0.95); }
transform: scale(0.95); &:hover { background-color: #F0F1F2; }
}
&:hover {
background-color: #F0F1F2;
}
} }
//
.upload-img-container { .upload-img-container {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 80%;
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: start; justify-content: start;
@ -625,16 +277,15 @@ watch(() => props.type, (newType) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
// gap: 40px;
position: relative; position: relative;
border: none; border: none;
box-shadow: none; box-shadow: none;
:deep(.el-sender) { :deep(.el-sender) {
border: none; border: none;
box-shadow: none; box-shadow: none;
} }
} }
.prefix-self-wrap { .prefix-self-wrap {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -642,12 +293,9 @@ watch(() => props.type, (newType) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 5px; gap: 5px;
img { height: 50px; border-radius: 4px; }
}
img{
height: 50px;
border-radius: 4px;
}
}
.title { .title {
background-color: #FFF; background-color: #FFF;
color: #333; color: #333;
@ -659,6 +307,7 @@ watch(() => props.type, (newType) => {
line-height: normal; line-height: normal;
margin-bottom: 106px; margin-bottom: 106px;
} }
:deep(.el-sender) { :deep(.el-sender) {
background-color: #F5F6F7; background-color: #F5F6F7;
border: none; border: none;
@ -672,13 +321,13 @@ watch(() => props.type, (newType) => {
:deep(.el-popover.el-popper) { :deep(.el-popover.el-popper) {
border-radius: 20px; border-radius: 20px;
} }
//
.select { .select {
background: #ffffff; background: #ffffff;
border-radius: 10px; border-radius: 10px;
border: 1px solid rgba(0, 0, 0, 0.10); border: 1px solid rgba(0, 0, 0, 0.10);
} }
//
.upload-btn { .upload-btn {
display: flex; display: flex;
height: 40px; height: 40px;
@ -692,10 +341,9 @@ watch(() => props.type, (newType) => {
cursor: pointer; cursor: pointer;
position: relative; position: relative;
} }
.upload-btn:hover{
background: #E5E7EB; .upload-btn:hover { background: #E5E7EB; }
}
/* 圆形按钮 */
.circle-btn { .circle-btn {
position: absolute; position: absolute;
right: 0px; right: 0px;
@ -711,18 +359,10 @@ watch(() => props.type, (newType) => {
transition: all 0.3s ease; transition: all 0.3s ease;
color: rgb(0, 0, 0); color: rgb(0, 0, 0);
font-size: 20px; font-size: 20px;
&:hover { transform: scale(1.1); }
&:hover { &:active { transform: scale(0.95); }
transform: scale(1.1);
// box-shadow: 0 6px 16px rgba(98, 106, 239, 0.6);
} }
&:active {
transform: scale(0.95);
}
}
/* 过渡动画 */
.slide-up-enter-active, .slide-up-enter-active,
.slide-up-leave-active { .slide-up-leave-active {
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
@ -748,7 +388,6 @@ watch(() => props.type, (newType) => {
border-radius: 10px; border-radius: 10px;
background: rgba(0, 15, 51, 0.10); background: rgba(0, 15, 51, 0.10);
cursor: pointer; cursor: pointer;
color: #000F33; color: #000F33;
text-align: center; text-align: center;
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
@ -757,35 +396,9 @@ watch(() => props.type, (newType) => {
font-weight: 700; font-weight: 700;
line-height: normal; line-height: normal;
} }
.isprompt { .isprompt {
color: #ffffff; color: #ffffff;
background-color: #000F33; background-color: #000F33;
} }
// .gerenate:hover{
// background: rgba(0, 15, 51, 0.20);
// }
//
.quality-select {
:deep(.select-header) {
height: 40px;
padding: 0 15px;
border-radius: 10px;
border: 1px solid #E8E9EB;
background: #f5f6f7;
&:hover {
background: #e9eaeb;
}
}
:deep(.select-text) {
font-size: 14px;
}
}
.quality-label {
font-family: "Microsoft YaHei";
font-size: 12px;
color: #999;
}
</style> </style>

View File

@ -1,22 +1,5 @@
import outPlatform from '@/config/index' // 所有平台 descriptor 的 buildTaskBody() 已直接返回扁平 modelParams
// 此文件仅做透传,后续可直接移除
// 构造任务 body
export async function createTask(data) { export async function createTask(data) {
// Painting 使用新架构:直接使用动态模型参数 return data.body
if (data.type === 'Painting') {
return data.modelParams || {}
}
// Video 继续使用旧 workflow 适配器
const payload = await outPlatform[data.platform].Playload(data)
return payload
}
// 获取结果
export async function getTask(result) {
if (result.code === 0 && result.msg === 'success' && Array.isArray(result.data) && result.data.length > 0) {
const urls = result.data.map(item => item.fileUrl)
return { type: true, urls: urls }
}
return { type: false, message: result.data.exception_message || '生成失败' }
} }