fix(canvas): 修复生成节点状态更新及参考图请求

保留选中参考图,按模型传递分辨率,让生成节点响应成功或失败状态并显示原因。

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
2026-10-12 12:24:28 +08:00
co-authored by Devin
parent 6354e629ad
commit 0631849c36
2 changed files with 33 additions and 15 deletions
@@ -143,7 +143,8 @@ defineExpose({ startEdit, commitNote })
</template>
<template v-else>
<span class="cv-node__x">✕</span>
<span class="cv-node__err" :title="node.error || ''">生成失败</span>
<span>生成失败</span>
<span class="cv-node__err" :title="node.error || ''">{{ node.error || '请检查提示词后重试' }}</span>
</template>
</div>
</div>
@@ -261,10 +262,13 @@ html.dark .cv-node__note { color: rgb(255 255 255 / 0.88); }
}
.cv-node__err {
font-size: 11px;
max-width: 90%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.5;
max-width: min(90%, 320px);
max-height: 5em;
overflow: auto;
overflow-wrap: anywhere;
text-align: center;
user-select: text;
}
.cv-port {
+24 -10
View File
@@ -34,6 +34,12 @@ const imageModels = computed(() =>
)
const model = computed(() => imageModels.value.find((m) => m.id === gen.modelId) || null)
const ratios = computed(() => model.value?.ratios?.length ? model.value.ratios : ['1:1'])
const resolutions = computed(() => model.value?.resolutions?.length
? model.value.resolutions
: Object.keys(model.value?.prices || {}))
const maxRefs = computed(() => Math.min(4, Math.max(
Number(model.value?.max_reference_images || 0), model.value?.image_to_image ? 1 : 0,
)))
const selectedImages = computed(() =>
selectionIds.value
.map((id) => doc.nodes.find((n) => n.id === id))
@@ -493,7 +499,7 @@ function onPaste(e) {
async function refToBase64(name) {
const res = await fetch(generatedUrl(name))
if (!res.ok) throw new Error('fetch ref failed')
if (!res.ok) throw new Error(`参考图加载失败 (${res.status}),请重新选择图片`)
const blob = await res.blob()
const dataUrl = await new Promise((resolve, reject) => {
const fr = new FileReader()
@@ -511,13 +517,18 @@ async function generate() {
genMsg.value = '请输入提示词,或选中一个有内容的笔记节点'
return
}
const images = selectedImages.value.slice(0, maxRefs.value)
if (selectedImages.value.length && !maxRefs.value) {
genMsg.value = '当前模型不支持参考图,请取消图片选择或切换模型'
return
}
genBusy.value = true
genMsg.value = ''
const size = ratioToSize(gen.ratio || ratios.value[0])
const sources = [
...selectedNotes.value,
...selectedImages.value.slice(0, 4),
...images,
]
// 落点:参与源节点的包围盒右侧;无源则视口中心
let x
@@ -537,23 +548,26 @@ async function generate() {
y = c.y - size.h / 2
}
const node = {
const node = reactive({
id: newId('g'), type: 'gen', status: 'running',
x: Math.round(x), y: Math.round(y), w: size.w, h: size.h, z: 0,
}
})
doc.nodes.push(node)
for (const s of sources) {
doc.edges.push({ id: newId('e'), from: s.id, to: node.id })
}
selectionIds.value = [node.id]
stage.value?.selectIds([node.id])
pushHistory()
try {
const payload = { model: gen.modelId, prompt, ratio: gen.ratio || ratios.value[0] }
if (selectedImages.value.length) {
payload.reference_images = await Promise.all(
selectedImages.value.slice(0, 4).map((n) => refToBase64(n.src).catch(() => null)),
).then((arr) => arr.filter(Boolean))
const payload = {
model: gen.modelId, prompt, ratio: gen.ratio || ratios.value[0],
resolution: resolutions.value[0] || '1K',
}
if (images.length) {
const refs = await Promise.all(images.map((n) => refToBase64(n.src)))
payload.reference_images = refs
}
const opts = jsonBody('POST', payload)
opts.headers['Idempotency-Key'] = node.id
@@ -834,7 +848,7 @@ const saveLabel = computed(() => ({
/>
<div class="cv-refs">
参考图:选中画布上的图片节点({{ selectedImages.length }}/4)
参考图:选中画布上的图片节点({{ selectedImages.length }}/{{ maxRefs }})
</div>
<button class="cv-gen" :disabled="genBusy || !model" @click="generate">