mcwl-pc/app/pages/web-ui/index.vue

215 lines
6.2 KiB
Vue

<script setup lang="ts">
import {
NCard,
NTabs,
NTabPane,
NSelect,
NInput,
NInputNumber,
NButton,
NSpace,
NGrid,
NGridItem,
NImage,
NTag
} from 'naive-ui'
// 模型列表
const models = ref([
{ label: 'Stable Diffusion v1.5', value: 'sd-v1.5' },
{ label: 'Stable Diffusion v2.1', value: 'sd-v2.1' },
{ label: 'Stable Diffusion XL', value: 'sd-xl' },
])
// 采样器选项
const samplers = ref([
{ label: 'Euler a', value: 'euler-a' },
{ label: 'DPM++ 2M Karras', value: 'dpm-2m-karras' },
{ label: 'DPM++ SDE Karras', value: 'dpm-sde-karras' },
])
// 表单数据
const formState = ref({
model: 'sd-v1.5',
prompt: '',
negativePrompt: '',
sampler: 'euler-a',
steps: 20,
cfgScale: 7,
width: 512,
height: 512,
seed: -1,
})
// 生成的图片列表
const generatedImages = ref([
{
id: 1,
url: 'https://placeholder.co/512x512',
prompt: 'a beautiful landscape',
params: { steps: 20, cfg: 7, sampler: 'Euler a' }
},
// ... 更多图片
])
// 生成图片方法
const generateImage = () => {
// TODO: 实现图片生成逻辑
console.log('Generating image with params:', formState.value)
}
</script>
<template>
<div class="min-h-full p-4">
<NCard title="在线生图" class="mb-4">
<NTabs type="segment" animated>
<!-- 文生图 -->
<NTabPane name="text2img" tab="文生图">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<!-- 左侧参数面板 -->
<div class="md:col-span-2 space-y-4">
<!-- 提示词输入 -->
<NInput
v-model:value="formState.prompt"
type="textarea"
placeholder="请输入图像提示词(英文)"
:autosize="{ minRows: 3, maxRows: 6 }"
/>
<!-- 反向提示词 -->
<NInput
v-model:value="formState.negativePrompt"
type="textarea"
placeholder="请输入反向提示词(英文)"
:autosize="{ minRows: 2, maxRows: 4 }"
/>
<!-- 基础参数 -->
<NGrid :cols="2" :x-gap="12" :y-gap="8">
<NGridItem>
<div class="flex flex-col gap-2">
<span class="text-sm">基础模型</span>
<NSelect
v-model:value="formState.model"
:options="models"
/>
</div>
</NGridItem>
<NGridItem>
<div class="flex flex-col gap-2">
<span class="text-sm">采样器</span>
<NSelect
v-model:value="formState.sampler"
:options="samplers"
/>
</div>
</NGridItem>
<NGridItem>
<div class="flex flex-col gap-2">
<span class="text-sm">采样步数</span>
<NInputNumber
v-model:value="formState.steps"
:min="1"
:max="150"
/>
</div>
</NGridItem>
<NGridItem>
<div class="flex flex-col gap-2">
<span class="text-sm">CFG Scale</span>
<NInputNumber
v-model:value="formState.cfgScale"
:min="1"
:max="30"
:step="0.5"
/>
</div>
</NGridItem>
<NGridItem>
<div class="flex flex-col gap-2">
<span class="text-sm">宽度</span>
<NInputNumber
v-model:value="formState.width"
:min="64"
:max="2048"
:step="64"
/>
</div>
</NGridItem>
<NGridItem>
<div class="flex flex-col gap-2">
<span class="text-sm">高度</span>
<NInputNumber
v-model:value="formState.height"
:min="64"
:max="2048"
:step="64"
/>
</div>
</NGridItem>
</NGrid>
<!-- 生成按钮 -->
<div class="flex justify-end">
<NButton type="primary" size="large" @click="generateImage">
</NButton>
</div>
</div>
<!-- -->
<div class="space-y-4">
<NCard title="实时预览" class="text-center">
<div class="aspect-square bg-gray-100 rounded-lg flex items-center justify-center">
<span class="text-gray-400">等待生成...</span>
</div>
</NCard>
</div>
</div>
</NTabPane>
<!-- 图生图 -->
<NTabPane name="img2img" tab="图生图">
<div class="flex items-center justify-center h-64">
<span class="text-gray-400">图生图功能开发中...</span>
</div>
</NTabPane>
</NTabs>
</NCard>
<!-- 历史记录 -->
<NCard title="生成历史" class="mb-4">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div v-for="image in generatedImages" :key="image.id" class="space-y-2">
<NImage
:src="image.url"
class="rounded-lg w-full aspect-square object-cover"
:preview-src="image.url"
/>
<div class="space-y-1">
<p class="text-sm text-gray-600 truncate">{{ image.prompt }}</p>
<div class="flex flex-wrap gap-1">
<NTag size="small" v-for="(value, key) in image.params" :key="key">
{{ key }}: {{ value }}
</NTag>
</div>
</div>
</div>
</div>
</NCard>
</div>
</template>
<style scoped>
.n-input {
min-width: 100%;
}
:deep(.n-card-header) {
padding: 12px 16px;
}
:deep(.n-tabs-tab) {
padding: 8px 16px;
}
</style>