fix: 修复按钮状态恢复、Music 任务内容显示与比例标签为空,新增 platform_code 参数
- taskPolling: isSubGerenate=true 提前至 modelId 校验前,确保错误时按钮恢复;请求体新增 platform_code - dialogBox: generateData 集成平台 getGenerateDataExtras 扩展字段 - Music 平台: 新增 getGenerateDataExtras() 输出 pureMusic/mode,供列表展示和再生成使用 - set.vue: 硬编码比例标签改为 secondTagText 计算属性,Music 显示纯音乐/有歌词,Painting/Video 从 modelParams 提取比例
This commit is contained in:
parent
4d76899488
commit
7379488839
@ -157,7 +157,8 @@ const handleStart = async () => {
|
|||||||
modelType: p.modelType.value,
|
modelType: p.modelType.value,
|
||||||
prompt: prompt.value,
|
prompt: prompt.value,
|
||||||
referenceImages: referenceImages.value,
|
referenceImages: referenceImages.value,
|
||||||
modelParams: body
|
modelParams: body,
|
||||||
|
...(p.getGenerateDataExtras?.() || {})
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { markRaw, reactive, ref, computed } from 'vue'
|
import { computed, markRaw, reactive, ref } from 'vue'
|
||||||
import { registerPlatform } from '@/platforms/registry.js'
|
|
||||||
import { fetchPlatformModels, getPlatformCode, getModelConfig, getModelId, preloadModelConfigs } from '@/utils/modelApi'
|
|
||||||
import { syncParamValues, checkShowWhen } from '@/utils/modelConfigHelper.js'
|
|
||||||
import ModelSelector from './modelSelector.vue'
|
|
||||||
import ImageUploader from './imageUploader.vue'
|
|
||||||
import ModeSelector from './controls/modeSelector.vue'
|
|
||||||
import PureMusicGroup from './controls/pureMusicGroup.vue'
|
|
||||||
import LyricsInput from './controls/lyricsInput.vue'
|
|
||||||
import TimeControl from './controls/timeControl.vue'
|
|
||||||
import ParamGroup from '@/components/ParamGroup/index.vue'
|
import ParamGroup from '@/components/ParamGroup/index.vue'
|
||||||
import Select from '@/components/Select/index.vue'
|
import Select from '@/components/Select/index.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { registerPlatform } from '@/platforms/registry.js'
|
||||||
|
import { fetchPlatformModels, getModelConfig, getModelId, getPlatformCode, preloadModelConfigs } from '@/utils/modelApi'
|
||||||
|
import { checkShowWhen } from '@/utils/modelConfigHelper.js'
|
||||||
|
import LyricsInput from './controls/lyricsInput.vue'
|
||||||
|
import ModeSelector from './controls/modeSelector.vue'
|
||||||
|
import PureMusicGroup from './controls/pureMusicGroup.vue'
|
||||||
|
import TimeControl from './controls/timeControl.vue'
|
||||||
|
import ImageUploader from './imageUploader.vue'
|
||||||
|
import ModelSelector from './modelSelector.vue'
|
||||||
|
|
||||||
// 由专用控件处理的 ui 类型
|
// 由专用控件处理的 ui 类型
|
||||||
const handledUis = ['textarea', 'proportion', 'imageUpload', 'hidden', 'quantity']
|
const handledUis = ['textarea', 'proportion', 'imageUpload', 'hidden', 'quantity']
|
||||||
@ -37,11 +36,11 @@ export function defineMusicPlatform() {
|
|||||||
async function loadModels() {
|
async function loadModels() {
|
||||||
models.value = await fetchPlatformModels(code.value)
|
models.value = await fetchPlatformModels(code.value)
|
||||||
if (!model.value && models.value.length) {
|
if (!model.value && models.value.length) {
|
||||||
const first = models.value.find(m => !m.disabled)
|
const first = models.value.find((m) => !m.disabled)
|
||||||
if (first) model.value = first.id
|
if (first) model.value = first.id
|
||||||
}
|
}
|
||||||
if (models.value.length) {
|
if (models.value.length) {
|
||||||
const ids = models.value.map(m => m.id)
|
const ids = models.value.map((m) => m.id)
|
||||||
preloadModelConfigs(ids)
|
preloadModelConfigs(ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,22 +64,22 @@ export function defineMusicPlatform() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 同步专用 ref
|
// 同步专用 ref
|
||||||
const modeParam = config.params.find(p => p.name === 'mode' || p.ui === 'mode')
|
const modeParam = config.params.find((p) => p.name === 'mode' || p.ui === 'mode')
|
||||||
if (modeParam) mode.value = modeParam.default || '常用模式'
|
if (modeParam) mode.value = modeParam.default || '常用模式'
|
||||||
|
|
||||||
const qtyParam = config.params.find(p => p.ui === 'quantity')
|
const qtyParam = config.params.find((p) => p.ui === 'quantity')
|
||||||
if (qtyParam) quantity.value = qtyParam.default || 1
|
if (qtyParam) quantity.value = qtyParam.default || 1
|
||||||
|
|
||||||
const durParam = config.params.find(p => p.name === 'duration')
|
const durParam = config.params.find((p) => p.name === 'duration')
|
||||||
if (durParam) duration.value = durParam.default || 'Auto'
|
if (durParam) duration.value = durParam.default || 'Auto'
|
||||||
|
|
||||||
const lyricsParam = config.params.find(p => p.name === 'lyrics')
|
const lyricsParam = config.params.find((p) => p.name === 'lyrics')
|
||||||
if (lyricsParam) lyrics.value = lyricsParam.default || ''
|
if (lyricsParam) lyrics.value = lyricsParam.default || ''
|
||||||
|
|
||||||
const seedParam = config.params.find(p => p.name === 'randomSeed' || p.name === 'seed')
|
const seedParam = config.params.find((p) => p.name === 'randomSeed' || p.name === 'seed')
|
||||||
if (seedParam) randomSeed.value = seedParam.default || ''
|
if (seedParam) randomSeed.value = seedParam.default || ''
|
||||||
|
|
||||||
const pmParam = config.params.find(p => p.name === 'pureMusic')
|
const pmParam = config.params.find((p) => p.name === 'pureMusic')
|
||||||
if (pmParam) pureMusic.value = pmParam.default !== undefined ? pmParam.default : true
|
if (pmParam) pureMusic.value = pmParam.default !== undefined ? pmParam.default : true
|
||||||
|
|
||||||
if (config.promptPlaceholder) {
|
if (config.promptPlaceholder) {
|
||||||
@ -93,7 +92,7 @@ export function defineMusicPlatform() {
|
|||||||
function imageUploadLimit() {
|
function imageUploadLimit() {
|
||||||
if (!modelConfig.value) return 0
|
if (!modelConfig.value) return 0
|
||||||
return modelConfig.value.params
|
return modelConfig.value.params
|
||||||
.filter(p => p.ui === 'imageUpload')
|
.filter((p) => p.ui === 'imageUpload')
|
||||||
.reduce((sum, p) => sum + (p.maxCount || 1), 0)
|
.reduce((sum, p) => sum + (p.maxCount || 1), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,12 +117,12 @@ export function defineMusicPlatform() {
|
|||||||
function buildTaskBody({ prompt, referenceImages }) {
|
function buildTaskBody({ prompt, referenceImages }) {
|
||||||
syncMusicParamValues()
|
syncMusicParamValues()
|
||||||
// 将 prompt 写入 paramValues(如果 config 中有 prompt 参数)
|
// 将 prompt 写入 paramValues(如果 config 中有 prompt 参数)
|
||||||
const promptParam = modelConfig.value?.params?.find(p => p.ui === 'textarea')
|
const promptParam = modelConfig.value?.params?.find((p) => p.ui === 'textarea')
|
||||||
if (promptParam) paramValues[promptParam.name] = prompt
|
if (promptParam) paramValues[promptParam.name] = prompt
|
||||||
|
|
||||||
// 将参考音频映射到 imageUpload 参数
|
// 将参考音频映射到 imageUpload 参数
|
||||||
if (modelConfig.value) {
|
if (modelConfig.value) {
|
||||||
const imageUploadParams = modelConfig.value.params.filter(p => p.ui === 'imageUpload')
|
const imageUploadParams = modelConfig.value.params.filter((p) => p.ui === 'imageUpload')
|
||||||
imageUploadParams.forEach((p, i) => {
|
imageUploadParams.forEach((p, i) => {
|
||||||
if (referenceAudio.value[i]) {
|
if (referenceAudio.value[i]) {
|
||||||
paramValues[p.name] = referenceAudio.value[i].url
|
paramValues[p.name] = referenceAudio.value[i].url
|
||||||
@ -133,26 +132,34 @@ export function defineMusicPlatform() {
|
|||||||
return { ...paramValues }
|
return { ...paramValues }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 附加平台专属字段到 generateData,用于任务列表展示和再次生成/重新编辑
|
||||||
|
function getGenerateDataExtras() {
|
||||||
|
return {
|
||||||
|
pureMusic: pureMusic.value,
|
||||||
|
mode: mode.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function syncMusicParamValues() {
|
function syncMusicParamValues() {
|
||||||
if (!modelConfig.value) return
|
if (!modelConfig.value) return
|
||||||
const config = modelConfig.value
|
const config = modelConfig.value
|
||||||
|
|
||||||
const qtyParam = config.params.find(p => p.ui === 'quantity')
|
const qtyParam = config.params.find((p) => p.ui === 'quantity')
|
||||||
if (qtyParam) paramValues[qtyParam.name] = quantity.value
|
if (qtyParam) paramValues[qtyParam.name] = quantity.value
|
||||||
|
|
||||||
const durParam = config.params.find(p => p.name === 'duration')
|
const durParam = config.params.find((p) => p.name === 'duration')
|
||||||
if (durParam) paramValues[durParam.name] = duration.value
|
if (durParam) paramValues[durParam.name] = duration.value
|
||||||
|
|
||||||
const lyricsParam = config.params.find(p => p.name === 'lyrics')
|
const lyricsParam = config.params.find((p) => p.name === 'lyrics')
|
||||||
if (lyricsParam) paramValues[lyricsParam.name] = lyrics.value
|
if (lyricsParam) paramValues[lyricsParam.name] = lyrics.value
|
||||||
|
|
||||||
const seedParam = config.params.find(p => p.name === 'randomSeed' || p.name === 'seed')
|
const seedParam = config.params.find((p) => p.name === 'randomSeed' || p.name === 'seed')
|
||||||
if (seedParam) paramValues[seedParam.name] = randomSeed.value
|
if (seedParam) paramValues[seedParam.name] = randomSeed.value
|
||||||
|
|
||||||
const pmParam = config.params.find(p => p.name === 'pureMusic')
|
const pmParam = config.params.find((p) => p.name === 'pureMusic')
|
||||||
if (pmParam) paramValues[pmParam.name] = pureMusic.value
|
if (pmParam) paramValues[pmParam.name] = pureMusic.value
|
||||||
|
|
||||||
const modeParam = config.params.find(p => p.name === 'mode' || p.ui === 'mode')
|
const modeParam = config.params.find((p) => p.name === 'mode' || p.ui === 'mode')
|
||||||
if (modeParam) paramValues[modeParam.name] = mode.value
|
if (modeParam) paramValues[modeParam.name] = mode.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,13 +178,13 @@ export function defineMusicPlatform() {
|
|||||||
name: 'modeSelector',
|
name: 'modeSelector',
|
||||||
component: markRaw(ModeSelector),
|
component: markRaw(ModeSelector),
|
||||||
beforeModel: true,
|
beforeModel: true,
|
||||||
show: (config) => !!config?.params?.find(p => p.name === 'mode' || p.ui === 'mode'),
|
show: (config) => !!config?.params?.find((p) => p.name === 'mode' || p.ui === 'mode'),
|
||||||
props: (config) => {
|
props: (config) => {
|
||||||
const modeParam = config?.params?.find(p => p.name === 'mode' || p.ui === 'mode')
|
const modeParam = config?.params?.find((p) => p.name === 'mode' || p.ui === 'mode')
|
||||||
return {
|
return {
|
||||||
modelValue: mode.value,
|
'modelValue': mode.value,
|
||||||
'onUpdate:modelValue': (v) => { mode.value = v },
|
'onUpdate:modelValue': (v) => { mode.value = v },
|
||||||
options: modeParam?.options || []
|
'options': modeParam?.options || []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -185,11 +192,11 @@ export function defineMusicPlatform() {
|
|||||||
name: 'pureMusicGroup',
|
name: 'pureMusicGroup',
|
||||||
component: markRaw(PureMusicGroup),
|
component: markRaw(PureMusicGroup),
|
||||||
beforeModel: false,
|
beforeModel: false,
|
||||||
show: (config) => mode.value === '常用模式' && !!config?.params?.find(p => p.name === 'pureMusic'),
|
show: (config) => mode.value === '常用模式' && !!config?.params?.find((p) => p.name === 'pureMusic'),
|
||||||
props: (config) => ({
|
props: (config) => ({
|
||||||
modelValue: pureMusic.value,
|
'modelValue': pureMusic.value,
|
||||||
'onUpdate:modelValue': (v) => { pureMusic.value = v },
|
'onUpdate:modelValue': (v) => { pureMusic.value = v },
|
||||||
lyrics: lyrics.value,
|
'lyrics': lyrics.value,
|
||||||
'onUpdate:lyrics': (v) => { lyrics.value = v }
|
'onUpdate:lyrics': (v) => { lyrics.value = v }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -197,9 +204,9 @@ export function defineMusicPlatform() {
|
|||||||
name: 'lyricsInput',
|
name: 'lyricsInput',
|
||||||
component: markRaw(LyricsInput),
|
component: markRaw(LyricsInput),
|
||||||
beforeModel: false,
|
beforeModel: false,
|
||||||
show: (config) => mode.value === '专业模式' && !!config?.params?.find(p => p.name === 'lyrics'),
|
show: (config) => mode.value === '专业模式' && !!config?.params?.find((p) => p.name === 'lyrics'),
|
||||||
props: (config) => ({
|
props: (config) => ({
|
||||||
modelValue: lyrics.value,
|
'modelValue': lyrics.value,
|
||||||
'onUpdate:modelValue': (v) => { lyrics.value = v }
|
'onUpdate:modelValue': (v) => { lyrics.value = v }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -207,14 +214,14 @@ export function defineMusicPlatform() {
|
|||||||
name: 'timeControl',
|
name: 'timeControl',
|
||||||
component: markRaw(TimeControl),
|
component: markRaw(TimeControl),
|
||||||
beforeModel: false,
|
beforeModel: false,
|
||||||
show: (config) => mode.value === '常用模式' && !!config?.params?.find(p => p.name === 'duration'),
|
show: (config) => mode.value === '常用模式' && !!config?.params?.find((p) => p.name === 'duration'),
|
||||||
props: (config) => {
|
props: (config) => {
|
||||||
const durParam = config?.params?.find(p => p.name === 'duration')
|
const durParam = config?.params?.find((p) => p.name === 'duration')
|
||||||
return {
|
return {
|
||||||
modelValue: duration.value,
|
'modelValue': duration.value,
|
||||||
'onUpdate:modelValue': (v) => { duration.value = v },
|
'onUpdate:modelValue': (v) => { duration.value = v },
|
||||||
min: durParam?.min || 10,
|
'min': durParam?.min || 10,
|
||||||
max: durParam?.max || 240
|
'max': durParam?.max || 240
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -222,15 +229,15 @@ export function defineMusicPlatform() {
|
|||||||
name: 'quantity',
|
name: 'quantity',
|
||||||
component: markRaw(Select),
|
component: markRaw(Select),
|
||||||
beforeModel: false,
|
beforeModel: false,
|
||||||
show: (config) => !!config?.params?.find(p => p.ui === 'quantity'),
|
show: (config) => !!config?.params?.find((p) => p.ui === 'quantity'),
|
||||||
props: (config) => {
|
props: (config) => {
|
||||||
const qtyParam = config?.params?.find(p => p.ui === 'quantity')
|
const qtyParam = config?.params?.find((p) => p.ui === 'quantity')
|
||||||
const maxQty = Math.max(...(qtyParam?.options || [1]))
|
const maxQty = Math.max(...(qtyParam?.options || [1]))
|
||||||
const limited = mode.value === '专业模式' ? 1 : maxQty
|
const limited = mode.value === '专业模式' ? 1 : maxQty
|
||||||
return {
|
return {
|
||||||
modelValue: quantity.value,
|
'modelValue': quantity.value,
|
||||||
'onUpdate:modelValue': (v) => { quantity.value = v },
|
'onUpdate:modelValue': (v) => { quantity.value = v },
|
||||||
options: Array.from({ length: limited }, (_, i) => ({ value: i + 1, label: `${i + 1}条` }))
|
'options': Array.from({ length: limited }, (_, i) => ({ value: i + 1, label: `${i + 1}条` }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -263,15 +270,36 @@ export function defineMusicPlatform() {
|
|||||||
controls,
|
controls,
|
||||||
ImageUploader: markRaw(ImageUploader),
|
ImageUploader: markRaw(ImageUploader),
|
||||||
state: {
|
state: {
|
||||||
model, modelType, mode, modelConfig, paramValues,
|
model,
|
||||||
promptPlaceholder, referenceAudio, models,
|
modelType,
|
||||||
quantity, duration, lyrics, randomSeed, pureMusic
|
mode,
|
||||||
|
modelConfig,
|
||||||
|
paramValues,
|
||||||
|
promptPlaceholder,
|
||||||
|
referenceAudio,
|
||||||
|
models,
|
||||||
|
quantity,
|
||||||
|
duration,
|
||||||
|
lyrics,
|
||||||
|
randomSeed,
|
||||||
|
pureMusic
|
||||||
},
|
},
|
||||||
model, modelType, mode, modelConfig, promptPlaceholder,
|
model,
|
||||||
loadModels, loadConfig, getDefaultModel,
|
modelType,
|
||||||
imageUploadLimit, validateBeforeSubmit,
|
mode,
|
||||||
getUploaderBindings, showImageUploader, isImageRequired,
|
modelConfig,
|
||||||
buildTaskBody, fillFromResult
|
promptPlaceholder,
|
||||||
|
loadModels,
|
||||||
|
loadConfig,
|
||||||
|
getDefaultModel,
|
||||||
|
imageUploadLimit,
|
||||||
|
validateBeforeSubmit,
|
||||||
|
getUploaderBindings,
|
||||||
|
showImageUploader,
|
||||||
|
isImageRequired,
|
||||||
|
buildTaskBody,
|
||||||
|
fillFromResult,
|
||||||
|
getGenerateDataExtras
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { ElNotification } from 'element-plus'
|
|||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { requestCreateTask, requestTaskStatus } from '@/apis/display'
|
import { requestCreateTask, requestTaskStatus } from '@/apis/display'
|
||||||
import { useDisplayStore, useUserStore } from '@/stores'
|
import { useDisplayStore, useUserStore } from '@/stores'
|
||||||
|
import { getPlatformCode } from '@/utils/modelApi'
|
||||||
import { userError } from '@/utils/tokenError'
|
import { userError } from '@/utils/tokenError'
|
||||||
|
|
||||||
export function getChargeType(chargeType) {
|
export function getChargeType(chargeType) {
|
||||||
@ -67,17 +68,18 @@ export async function generate(data, generateData) {
|
|||||||
let taskId = null
|
let taskId = null
|
||||||
let pollInterval = null
|
let pollInterval = null
|
||||||
|
|
||||||
|
useDisplay.isSubGerenate = true
|
||||||
|
|
||||||
if (!data.modelId) {
|
if (!data.modelId) {
|
||||||
ElNotification({
|
ElNotification({
|
||||||
title: '生成失败',
|
title: '生成失败',
|
||||||
message: h('i', { style: 'color: teal' }, '未找到模型ID,请联系管理员配置'),
|
message: h('i', { style: 'color: teal' }, '未找到模型ID,请联系管理员配置'),
|
||||||
type: 'error'
|
type: 'error'
|
||||||
})
|
})
|
||||||
|
useDisplay.isSubGerenate = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
useDisplay.isSubGerenate = true
|
|
||||||
|
|
||||||
// 从登录态获取 sessionId
|
// 从登录态获取 sessionId
|
||||||
const sessionId = useUserStore().userInfo.sessionId
|
const sessionId = useUserStore().userInfo.sessionId
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
@ -97,7 +99,8 @@ export async function generate(data, generateData) {
|
|||||||
const requestBody = {
|
const requestBody = {
|
||||||
model_id: data.modelId,
|
model_id: data.modelId,
|
||||||
body,
|
body,
|
||||||
request: data.request
|
request: data.request,
|
||||||
|
platform_code: getPlatformCode(data.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST 创建任务
|
// POST 创建任务
|
||||||
|
|||||||
@ -10,13 +10,13 @@
|
|||||||
</span>
|
</span>
|
||||||
<div :style="{ visibility: !isHovering && !showExternalGenerateData ? 'visible' : 'hidden' }" class="generate-data internal">
|
<div :style="{ visibility: !isHovering && !showExternalGenerateData ? 'visible' : 'hidden' }" class="generate-data internal">
|
||||||
<div class="detailed-data first-detailed-data">{{ props.item.generateData.model }}</div>
|
<div class="detailed-data first-detailed-data">{{ props.item.generateData.model }}</div>
|
||||||
<div class="detailed-data">{{ props.item.generateData.proportion }}</div>
|
<div class="detailed-data">{{ secondTagText }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="!isHovering && showExternalGenerateData" class="generate-data external">
|
<div v-show="!isHovering && showExternalGenerateData" class="generate-data external">
|
||||||
<div class="detailed-data first-detailed-data">{{ props.item.generateData.model }}</div>
|
<div class="detailed-data first-detailed-data">{{ props.item.generateData.model }}</div>
|
||||||
<div class="detailed-data">{{ props.item.generateData.proportion }}</div>
|
<div class="detailed-data">{{ secondTagText }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -212,6 +212,22 @@ const generateStatusText = computed(() => {
|
|||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 根据平台类型动态生成第二个标签文本
|
||||||
|
const secondTagText = computed(() => {
|
||||||
|
const gd = props.item.generateData
|
||||||
|
if (props.item.type === 'Music') {
|
||||||
|
if (gd.pureMusic === true) return '纯音乐'
|
||||||
|
if (gd.pureMusic === false) return '有歌词'
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
// Painting/Video:尝试从 modelParams 中提取比例信息
|
||||||
|
const params = gd.modelParams || {}
|
||||||
|
const key = Object.keys(params).find((k) =>
|
||||||
|
['aspectRatio', 'ratio', 'proportion'].includes(k)
|
||||||
|
)
|
||||||
|
return key ? params[key] : ''
|
||||||
|
})
|
||||||
|
|
||||||
const AIbrush = (file, index) => {
|
const AIbrush = (file, index) => {
|
||||||
emit('open-canvas', {
|
emit('open-canvas', {
|
||||||
mainImage: { url: file, index: index + 1 },
|
mainImage: { url: file, index: index + 1 },
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user