基于多图生成图片模型
This commit is contained in:
@@ -73,3 +73,12 @@ export function removeWatermark(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 图像处理接口
|
||||
export function imageProcessing(data) {
|
||||
return request({
|
||||
url: '/image-model/image-background',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ export const constantRoutes = [
|
||||
path: 'background-model',
|
||||
name: 'BackgroundModel',
|
||||
component: () => import('@/views/image-model/background-model'),
|
||||
meta: { title: '图像背景模型', icon: 'el-icon-picture-outline' }
|
||||
meta: { title: '图像智聚', icon: 'el-icon-picture-outline' }
|
||||
},
|
||||
{
|
||||
path: 'virtual-model',
|
||||
|
||||
@@ -1,26 +1,844 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>图像背景模型</span>
|
||||
<div class="content">
|
||||
<el-form :model="form" class="image-form">
|
||||
<!-- 主图选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>主图选择</h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
<!-- 左列:下拉框和提示词 -->
|
||||
<div class="left-column">
|
||||
<div class="selector-wrapper">
|
||||
<el-select
|
||||
v-model="form.baseImageId"
|
||||
placeholder="请选择主图"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
@change="handleBaseImageChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageList"
|
||||
:key="item.uuid"
|
||||
:label="item.imageName"
|
||||
:value="item.uuid"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<el-empty description="功能建设中,敬请期待" />
|
||||
<!-- 右列:图片预览 -->
|
||||
<div class="right-column">
|
||||
<div v-if="selectedImage" class="image-preview">
|
||||
<img
|
||||
:src="selectedImage.materialTempUrl"
|
||||
:alt="selectedImage.imageName"
|
||||
class="preview-image"
|
||||
@error="handleImageError"
|
||||
>
|
||||
<div class="image-details">
|
||||
<p><strong>{{ selectedImage.imageName }}</strong></p>
|
||||
<p>{{ selectedImage.ownerName }}</p>
|
||||
<p>{{ getImageTypeText(selectedImage.imageType) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 参考图选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>参考图选择</h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
<!-- 左列:下拉框和提示词 -->
|
||||
<div class="left-column">
|
||||
<div class="selector-wrapper">
|
||||
<el-select
|
||||
v-model="form.refImageId"
|
||||
placeholder="请选择参考图"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
@change="handleRefImageChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageList"
|
||||
:key="item.uuid"
|
||||
:label="item.imageName"
|
||||
:value="item.uuid"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="prompt-container">
|
||||
<el-input
|
||||
v-model="form.refPrompt"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入参考图提示词"
|
||||
class="prompt-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列:图片预览 -->
|
||||
<div class="right-column">
|
||||
<div v-if="selectedRefImage" class="image-preview">
|
||||
<img
|
||||
:src="selectedRefImage.materialTempUrl"
|
||||
:alt="selectedRefImage.imageName"
|
||||
class="preview-image"
|
||||
@error="handleImageError"
|
||||
>
|
||||
<div class="image-details">
|
||||
<p><strong>{{ selectedRefImage.imageName }}</strong></p>
|
||||
<p>{{ selectedRefImage.ownerName }}</p>
|
||||
<p>{{ getImageTypeText(selectedRefImage.imageType) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 前景边缘图1选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>前景边缘图1选择</h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
<!-- 左列:下拉框和提示词 -->
|
||||
<div class="left-column">
|
||||
<div class="selector-wrapper">
|
||||
<el-select
|
||||
v-model="form.foregroundEdge1Id"
|
||||
placeholder="请选择前景边缘图1"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
@change="handleForegroundEdge1Change"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageList"
|
||||
:key="item.uuid"
|
||||
:label="item.imageName"
|
||||
:value="item.uuid"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="prompt-container">
|
||||
<el-input
|
||||
v-model="form.foregroundEdge1Prompt"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入前景边缘图1提示词"
|
||||
class="prompt-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列:图片预览 -->
|
||||
<div class="right-column">
|
||||
<div v-if="selectedForegroundEdge1" class="image-preview">
|
||||
<img
|
||||
:src="selectedForegroundEdge1.materialTempUrl"
|
||||
:alt="selectedForegroundEdge1.imageName"
|
||||
class="preview-image"
|
||||
@error="handleImageError"
|
||||
>
|
||||
<div class="image-details">
|
||||
<p><strong>{{ selectedForegroundEdge1.imageName }}</strong></p>
|
||||
<p>{{ selectedForegroundEdge1.ownerName }}</p>
|
||||
<p>{{ getImageTypeText(selectedForegroundEdge1.imageType) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 前景边缘图2选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>前景边缘图2选择</h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
<!-- 左列:下拉框和提示词 -->
|
||||
<div class="left-column">
|
||||
<div class="selector-wrapper">
|
||||
<el-select
|
||||
v-model="form.foregroundEdge2Id"
|
||||
placeholder="请选择前景边缘图2"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
@change="handleForegroundEdge2Change"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageList"
|
||||
:key="item.uuid"
|
||||
:label="item.imageName"
|
||||
:value="item.uuid"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="prompt-container">
|
||||
<el-input
|
||||
v-model="form.foregroundEdge2Prompt"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入前景边缘图2提示词"
|
||||
class="prompt-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列:图片预览 -->
|
||||
<div class="right-column">
|
||||
<div v-if="selectedForegroundEdge2" class="image-preview">
|
||||
<img
|
||||
:src="selectedForegroundEdge2.materialTempUrl"
|
||||
:alt="selectedForegroundEdge2.imageName"
|
||||
class="preview-image"
|
||||
@error="handleImageError"
|
||||
>
|
||||
<div class="image-details">
|
||||
<p><strong>{{ selectedForegroundEdge2.imageName }}</strong></p>
|
||||
<p>{{ selectedForegroundEdge2.ownerName }}</p>
|
||||
<p>{{ getImageTypeText(selectedForegroundEdge2.imageType) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 背景边缘图选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>背景边缘图选择</h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
<!-- 左列:下拉框和提示词 -->
|
||||
<div class="left-column">
|
||||
<div class="selector-wrapper">
|
||||
<el-select
|
||||
v-model="form.backgroundEdgeId"
|
||||
placeholder="请选择背景边缘图"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
@change="handleBackgroundEdgeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageList"
|
||||
:key="item.uuid"
|
||||
:label="item.imageName"
|
||||
:value="item.uuid"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="prompt-container">
|
||||
<el-input
|
||||
v-model="form.backgroundEdgePrompt"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入背景边缘图提示词"
|
||||
class="prompt-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列:图片预览 -->
|
||||
<div class="right-column">
|
||||
<div v-if="selectedBackgroundEdge" class="image-preview">
|
||||
<img
|
||||
:src="selectedBackgroundEdge.materialTempUrl"
|
||||
:alt="selectedBackgroundEdge.imageName"
|
||||
class="preview-image"
|
||||
@error="handleImageError"
|
||||
>
|
||||
<div class="image-details">
|
||||
<p><strong>{{ selectedBackgroundEdge.imageName }}</strong></p>
|
||||
<p>{{ selectedBackgroundEdge.ownerName }}</p>
|
||||
<p>{{ getImageTypeText(selectedBackgroundEdge.imageType) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 生成参数区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>生成参数</h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="parameter-container">
|
||||
<div class="parameter-row">
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">张数 (n)</label>
|
||||
<el-input-number
|
||||
v-model="form.n"
|
||||
:min="1"
|
||||
:max="100"
|
||||
placeholder="请输入张数"
|
||||
class="parameter-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">参考提示词权重</label>
|
||||
<el-input-number
|
||||
v-model="form.refPromptWeight"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:precision="2"
|
||||
:step="0.1"
|
||||
placeholder="请输入权重"
|
||||
class="parameter-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">模型版本</label>
|
||||
<el-input
|
||||
v-model="form.modelVersion"
|
||||
placeholder="请输入模型版本"
|
||||
class="parameter-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="parameter-row">
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">所有人姓名</label>
|
||||
<el-input
|
||||
v-model="form.ownerName"
|
||||
placeholder="请输入所有人姓名"
|
||||
class="parameter-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">所有人电话</label>
|
||||
<el-input
|
||||
v-model="form.ownerPhone"
|
||||
placeholder="请输入所有人电话"
|
||||
class="parameter-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:loading="generateLoading"
|
||||
class="generate-button"
|
||||
@click="handleGenerate"
|
||||
>
|
||||
<i class="el-icon-magic-stick" />
|
||||
生成图像
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getImageList, imageProcessing } from '@/api/image-management'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'BackgroundModel'
|
||||
name: 'BackgroundModel',
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
// 主图选择
|
||||
baseImageId: '',
|
||||
// 参考图选择
|
||||
refImageId: '',
|
||||
refPrompt: '',
|
||||
// 前景边缘图选择
|
||||
foregroundEdge1Id: '',
|
||||
foregroundEdge2Id: '',
|
||||
foregroundEdge1Prompt: '',
|
||||
foregroundEdge2Prompt: '',
|
||||
// 背景边缘图选择
|
||||
backgroundEdgeId: '',
|
||||
backgroundEdgePrompt: '',
|
||||
// 生成参数
|
||||
n: 1,
|
||||
refPromptWeight: 0.5,
|
||||
modelVersion: 'v3',
|
||||
// 所有人信息
|
||||
ownerName: '',
|
||||
ownerPhone: ''
|
||||
},
|
||||
imageList: [],
|
||||
imageListLoading: false,
|
||||
generateLoading: false,
|
||||
selectedBaseImage: null,
|
||||
selectedRefImage: null,
|
||||
selectedForegroundEdge1: null,
|
||||
selectedForegroundEdge2: null,
|
||||
selectedBackgroundEdge: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['name', 'phone'])
|
||||
},
|
||||
created() {
|
||||
this.loadImageList()
|
||||
this.setDefaultUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 设置默认用户信息
|
||||
setDefaultUserInfo() {
|
||||
if (this.name) {
|
||||
this.form.ownerName = this.name
|
||||
}
|
||||
if (this.phone) {
|
||||
this.form.ownerPhone = this.phone
|
||||
}
|
||||
},
|
||||
|
||||
// 加载图像列表
|
||||
loadImageList() {
|
||||
this.imageListLoading = true
|
||||
const params = {
|
||||
current: 1,
|
||||
size: 20
|
||||
}
|
||||
|
||||
getImageList(params).then(response => {
|
||||
console.log('图像列表响应:', response)
|
||||
console.log('响应数据结构:', {
|
||||
success: response.success,
|
||||
data: response.data,
|
||||
total: response.total,
|
||||
message: response.message
|
||||
})
|
||||
|
||||
// 检查响应是否成功 - 参考图像管理列表的处理方式
|
||||
const isSuccess = response.success === true || (response.data && response.data.length >= 0)
|
||||
console.log('判断是否成功:', {
|
||||
'response.success': response.success,
|
||||
'response.data存在': !!response.data,
|
||||
'isSuccess': isSuccess
|
||||
})
|
||||
|
||||
if (isSuccess) {
|
||||
// 根据后端返回的数据结构,数据在response.data中
|
||||
console.log('原始数据:', response.data)
|
||||
this.imageList = response.data || []
|
||||
console.log('设置后的图像列表:', this.imageList)
|
||||
} else {
|
||||
console.error('获取图像列表失败:', response.message)
|
||||
this.$message.error(response.message || '获取图像列表失败')
|
||||
this.imageList = []
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取图像列表异常:', error)
|
||||
this.$message.error('获取图像列表失败: ' + error.message)
|
||||
this.imageList = []
|
||||
}).finally(() => {
|
||||
this.imageListLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 处理主图选择变化
|
||||
handleBaseImageChange(imageId) {
|
||||
console.log('选择的主图ID:', imageId)
|
||||
if (imageId) {
|
||||
this.selectedBaseImage = this.imageList.find(item => item.uuid === imageId)
|
||||
console.log('选中的主图信息:', this.selectedBaseImage)
|
||||
} else {
|
||||
this.selectedBaseImage = null
|
||||
}
|
||||
},
|
||||
|
||||
// 处理参考图选择变化
|
||||
handleRefImageChange(refImageId) {
|
||||
console.log('选择的参考图ID:', refImageId)
|
||||
if (refImageId) {
|
||||
this.selectedRefImage = this.imageList.find(item => item.uuid === refImageId)
|
||||
console.log('选中的参考图信息:', this.selectedRefImage)
|
||||
} else {
|
||||
this.selectedRefImage = null
|
||||
}
|
||||
},
|
||||
|
||||
// 处理前景边缘图1选择变化
|
||||
handleForegroundEdge1Change(edge1Id) {
|
||||
console.log('选择的前景边缘图1 ID:', edge1Id)
|
||||
if (edge1Id) {
|
||||
this.selectedForegroundEdge1 = this.imageList.find(item => item.uuid === edge1Id)
|
||||
console.log('选中的前景边缘图1信息:', this.selectedForegroundEdge1)
|
||||
} else {
|
||||
this.selectedForegroundEdge1 = null
|
||||
}
|
||||
},
|
||||
|
||||
// 处理前景边缘图2选择变化
|
||||
handleForegroundEdge2Change(edge2Id) {
|
||||
console.log('选择的前景边缘图2 ID:', edge2Id)
|
||||
if (edge2Id) {
|
||||
this.selectedForegroundEdge2 = this.imageList.find(item => item.uuid === edge2Id)
|
||||
console.log('选中的前景边缘图2信息:', this.selectedForegroundEdge2)
|
||||
} else {
|
||||
this.selectedForegroundEdge2 = null
|
||||
}
|
||||
},
|
||||
|
||||
// 处理背景边缘图选择变化
|
||||
handleBackgroundEdgeChange(backgroundEdgeId) {
|
||||
console.log('选择的背景边缘图ID:', backgroundEdgeId)
|
||||
if (backgroundEdgeId) {
|
||||
this.selectedBackgroundEdge = this.imageList.find(item => item.uuid === backgroundEdgeId)
|
||||
console.log('选中的背景边缘图信息:', this.selectedBackgroundEdge)
|
||||
} else {
|
||||
this.selectedBackgroundEdge = null
|
||||
}
|
||||
},
|
||||
|
||||
// 处理图片加载错误
|
||||
handleImageError(event) {
|
||||
console.error('图片加载失败:', event)
|
||||
this.$message.error('图片加载失败,请检查图片URL')
|
||||
},
|
||||
|
||||
// 获取图片类型文本
|
||||
getImageTypeText(type) {
|
||||
const typeMap = {
|
||||
background: '背景图',
|
||||
person: '人物图',
|
||||
product: '产品图',
|
||||
material: '素材图',
|
||||
other: '其他'
|
||||
}
|
||||
return typeMap[type] || '未知'
|
||||
},
|
||||
|
||||
// 处理生成按钮点击
|
||||
handleGenerate() {
|
||||
// 验证必填项
|
||||
if (!this.form.baseImageId) {
|
||||
this.$message.warning('请选择主图')
|
||||
return
|
||||
}
|
||||
if (!this.form.refImageId) {
|
||||
this.$message.warning('请选择参考图')
|
||||
return
|
||||
}
|
||||
if (!this.form.foregroundEdge1Id) {
|
||||
this.$message.warning('请选择前景边缘图1')
|
||||
return
|
||||
}
|
||||
if (!this.form.foregroundEdge2Id) {
|
||||
this.$message.warning('请选择前景边缘图2')
|
||||
return
|
||||
}
|
||||
if (!this.form.backgroundEdgeId) {
|
||||
this.$message.warning('请选择背景边缘图')
|
||||
return
|
||||
}
|
||||
|
||||
// 开始生成
|
||||
this.generateLoading = true
|
||||
|
||||
// 构建后端参数结构
|
||||
const requestData = {
|
||||
base_image_url: this.selectedBaseImage.materialTempUrl,
|
||||
ref_image_url: this.selectedRefImage.materialTempUrl,
|
||||
ref_prompt: this.form.refPrompt,
|
||||
reference_edge: {
|
||||
foreground_edge: [
|
||||
this.selectedForegroundEdge1.materialTempUrl,
|
||||
this.selectedForegroundEdge2.materialTempUrl
|
||||
],
|
||||
background_edge: [
|
||||
this.selectedBackgroundEdge.materialTempUrl
|
||||
],
|
||||
foreground_edge_prompt: [
|
||||
this.form.foregroundEdge1Prompt,
|
||||
this.form.foregroundEdge2Prompt
|
||||
],
|
||||
background_edge_prompt: [
|
||||
this.form.backgroundEdgePrompt
|
||||
]
|
||||
},
|
||||
parameters: {
|
||||
n: this.form.n,
|
||||
ref_prompt_weight: this.form.refPromptWeight,
|
||||
model_version: this.form.modelVersion
|
||||
},
|
||||
owner_info: {
|
||||
owner_name: this.form.ownerName,
|
||||
owner_phone: this.form.ownerPhone
|
||||
}
|
||||
}
|
||||
|
||||
console.log('开始生成图像,参数:', requestData)
|
||||
|
||||
// 调用后端接口
|
||||
imageProcessing(requestData).then(response => {
|
||||
this.generateLoading = false
|
||||
|
||||
if (response.success) {
|
||||
this.$message.success(response.message || '图像处理完成')
|
||||
console.log('图像处理成功,返回数据:', response)
|
||||
|
||||
// 处理返回的图片数据
|
||||
if (response.processedImages && response.processedImages.length > 0) {
|
||||
console.log('生成的图片:', response.processedImages)
|
||||
this.$message.info(`成功生成 ${response.processedImages.length} 张图像`)
|
||||
}
|
||||
|
||||
// 显示处理信息
|
||||
if (response.processingTimeMs) {
|
||||
console.log('处理时间:', response.processingTimeMs + 'ms')
|
||||
}
|
||||
if (response.requestId) {
|
||||
console.log('请求ID:', response.requestId)
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response.message || '图像处理失败')
|
||||
console.error('图像处理失败:', response)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.generateLoading = false
|
||||
console.error('调用图像处理接口失败:', error)
|
||||
this.$message.error('调用图像处理接口失败:' + (error.message || '未知错误'))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.image-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 30px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 15px 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.section-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.section-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.two-column-layout {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.left-column {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.right-column {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.selector-wrapper {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.image-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 15px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
background: #f8f9fa;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #dcdfe6;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.image-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.image-details p {
|
||||
margin: 0 0 4px 0;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.image-details p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.image-details strong {
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prompt-container {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.prompt-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.prompt-input .el-textarea__inner {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #dcdfe6;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.prompt-input .el-textarea__inner:focus {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
/* 参数区域样式 */
|
||||
.parameter-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.parameter-row {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.parameter-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.parameter-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.parameter-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.generate-button {
|
||||
padding: 12px 40px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.generate-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.generate-button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.app-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.two-column-layout {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.left-column,
|
||||
.right-column {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section-content {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.parameter-row {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.generate-button {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user