feat: 接入形态图库与 Seedream 生图操作
展示已有主图、候选图和失败记录,支持单图及批量生成、主图选择。 补充正式 ID 校验、费用确认、图片加载占位和回归测试。 依赖后端 eac8dc3 的项目形态图库只读接口。
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { AppDialog } from '../../../components/ui'
|
||||
import { primaryImage, validImageSize } from '../model'
|
||||
import type { GenerateFormImageInput, SubjectFormAsset } from '../types'
|
||||
|
||||
/** 单形态生成确认:尺寸与自定义 Prompt 只用于本次请求。 */
|
||||
const props = defineProps<{ form: SubjectFormAsset | null; disabled: boolean }>()
|
||||
const open = defineModel<boolean>('open', { default: false })
|
||||
const emit = defineEmits<{ generate: [formId: string, input: GenerateFormImageInput] }>()
|
||||
const prompt = ref('')
|
||||
const width = ref<number | ''>('')
|
||||
const height = ref<number | ''>('')
|
||||
const setPrimary = ref(false)
|
||||
const acknowledged = ref(false)
|
||||
const dimensionsValid = computed(() => validImageSize(width.value, height.value))
|
||||
const hasPrompt = computed(
|
||||
() => !!(prompt.value.trim() || (props.form?.generationPrompt ?? props.form?.appearancePrompt ?? '').trim())
|
||||
)
|
||||
|
||||
/** 每次打开重新建立表单,避免把另一形态的 Prompt 或尺寸带入请求。 */
|
||||
watch(
|
||||
() => [open.value, props.form?.id],
|
||||
() => {
|
||||
prompt.value = ''
|
||||
width.value = ''
|
||||
height.value = ''
|
||||
acknowledged.value = false
|
||||
setPrimary.value = props.form ? !primaryImage(props.form.images) : false
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
/** 完成前置确认后只发出一次明确的生图请求,不触发整条生产流程。 */
|
||||
function submit() {
|
||||
if (!props.form || props.disabled || !dimensionsValid.value || !hasPrompt.value || !acknowledged.value) return
|
||||
emit('generate', props.form.id, {
|
||||
provider: 'seedream',
|
||||
setPrimary: setPrimary.value,
|
||||
...(prompt.value.trim() ? { prompt: prompt.value.trim() } : {}),
|
||||
...(width.value !== '' && height.value !== '' ? { width: width.value, height: height.value } : {})
|
||||
})
|
||||
open.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppDialog
|
||||
v-model:open="open"
|
||||
title="生成形态图片"
|
||||
:description="`${form?.subject.name || ''} · ${form?.name || ''}`"
|
||||
>
|
||||
<form class="mt-6 space-y-5" @submit.prevent="submit">
|
||||
<p class="alert text-xs">使用后端配置的 Seedream 模型,可能产生费用。每次新增一张图片,不删除历史结果。</p>
|
||||
<label class="block"
|
||||
><span class="field-label">自定义提示词(可选,仅用于本次)</span
|
||||
><textarea
|
||||
id="image-prompt"
|
||||
v-model="prompt"
|
||||
class="input min-h-28"
|
||||
placeholder="留空使用已保存的 generationPrompt,其次使用 appearancePrompt"
|
||||
/>
|
||||
</label>
|
||||
<details v-if="form?.generationPrompt || form?.appearancePrompt" class="text-xs">
|
||||
<summary class="cursor-pointer text-muted">查看后端默认提示词</summary>
|
||||
<p class="mt-3 whitespace-pre-wrap leading-6">{{ form.generationPrompt ?? form.appearancePrompt }}</p>
|
||||
</details>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<label
|
||||
><span class="field-label">宽度(px)</span
|
||||
><input
|
||||
id="image-width"
|
||||
v-model.number="width"
|
||||
class="input"
|
||||
type="number"
|
||||
min="1"
|
||||
step="1"
|
||||
placeholder="后端默认" /></label
|
||||
><label
|
||||
><span class="field-label">高度(px)</span
|
||||
><input
|
||||
id="image-height"
|
||||
v-model.number="height"
|
||||
class="input"
|
||||
type="number"
|
||||
min="1"
|
||||
step="1"
|
||||
placeholder="后端默认"
|
||||
/></label>
|
||||
</div>
|
||||
<p class="text-xs text-muted">宽高同时留空时使用后端默认 2K;自定义尺寸须满足模型限制。</p>
|
||||
<p v-if="!dimensionsValid" class="text-xs text-danger" role="alert">宽高需要同时填写正整数,或同时留空。</p>
|
||||
<p v-if="!hasPrompt" class="text-xs text-danger" role="alert">当前形态没有可用提示词,请填写本次提示词。</p>
|
||||
<label class="flex gap-2 text-sm"
|
||||
><input v-model="setPrimary" type="checkbox" class="accent-accent" />生成成功后设为此形态主参考图</label
|
||||
>
|
||||
<p v-if="setPrimary && form && primaryImage(form.images)" class="text-xs text-muted">
|
||||
会替换当前主图标记,旧图片保留。已有视频提示词不会自动更新。
|
||||
</p>
|
||||
<label class="flex items-start gap-2 text-xs leading-6"
|
||||
><input
|
||||
id="confirm-image-cost"
|
||||
v-model="acknowledged"
|
||||
type="checkbox"
|
||||
class="mt-1.5 accent-accent"
|
||||
/>我已确认后台没有同项目的生成任务,了解本次会调用模型并产生费用。</label
|
||||
>
|
||||
<div class="dialog-footer">
|
||||
<button type="button" class="button button-secondary" @click="open = false">取消</button
|
||||
><button
|
||||
type="submit"
|
||||
class="button button-primary"
|
||||
:disabled="disabled || !acknowledged || !dimensionsValid || !hasPrompt"
|
||||
>
|
||||
确认生成图片
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</AppDialog>
|
||||
</template>
|
||||
Reference in New Issue
Block a user