多图生成图片
This commit is contained in:
@@ -5,7 +5,7 @@ export function getImageList(params) {
|
||||
return request({
|
||||
url: '/image-model/page',
|
||||
method: 'post',
|
||||
params: params // 使用params而不是data,这样参数会作为URL查询参数传递
|
||||
params: params // 使用params传递URL查询参数,因为后端使用@RequestParam
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,6 +79,16 @@ export function imageProcessing(data) {
|
||||
return request({
|
||||
url: '/image-model/image-background',
|
||||
method: 'post',
|
||||
data
|
||||
data,
|
||||
timeout: 60000 // 设置60秒超时,图像处理可能需要较长时间
|
||||
})
|
||||
}
|
||||
|
||||
// 检查任务状态
|
||||
export function checkImageModelStatus() {
|
||||
return request({
|
||||
url: '/image-model/check-status',
|
||||
method: 'post',
|
||||
timeout: 30000 // 设置30秒超时
|
||||
})
|
||||
}
|
||||
|
||||
75
src/image-management.js
Normal file
75
src/image-management.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取图像管理列表
|
||||
export function getImageList(params) {
|
||||
return request({
|
||||
url: '/image-model/page',
|
||||
method: 'post',
|
||||
params: params // 使用params而不是data,这样参数会作为URL查询参数传递
|
||||
})
|
||||
}
|
||||
|
||||
// 获取图像详情
|
||||
export function getImageDetail(id) {
|
||||
return request({
|
||||
url: `/api/image-management/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 创建图像
|
||||
export function createImage(data) {
|
||||
return request({
|
||||
url: '/api/image-management',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新图像
|
||||
export function updateImage(id, data) {
|
||||
return request({
|
||||
url: `/api/image-management/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除图像
|
||||
export function deleteImage(uuid) {
|
||||
return request({
|
||||
url: `/image-model/delete/${uuid}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量删除图像
|
||||
export function batchDeleteImages(ids) {
|
||||
return request({
|
||||
url: '/api/image-management/batch-delete',
|
||||
method: 'post',
|
||||
data: { ids }
|
||||
})
|
||||
}
|
||||
|
||||
// 上传素材
|
||||
export function uploadMaterial(formData, params = {}) {
|
||||
return request({
|
||||
url: '/image-model/upload',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
params: params, // 添加查询参数
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 去除水印
|
||||
export function removeWatermark(data) {
|
||||
return request({
|
||||
url: '/image-model/removeWatermar',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -14,6 +14,12 @@ const service = axios.create({
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// do something before request is sent
|
||||
console.log('请求配置:', {
|
||||
url: config.url,
|
||||
method: config.method,
|
||||
data: config.data,
|
||||
params: config.params
|
||||
})
|
||||
|
||||
if (store.getters.token) {
|
||||
// 使用Bearer token格式
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<!-- 主图选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>主图选择</h3>
|
||||
<h3>主图选择 <span class="required-tag">(必选)</span></h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
@@ -18,6 +18,9 @@
|
||||
placeholder="请选择主图"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleBaseImageSearch"
|
||||
@change="handleBaseImageChange"
|
||||
>
|
||||
<el-option
|
||||
@@ -32,17 +35,17 @@
|
||||
|
||||
<!-- 右列:图片预览 -->
|
||||
<div class="right-column">
|
||||
<div v-if="selectedImage" class="image-preview">
|
||||
<div v-if="selectedBaseImage" class="image-preview">
|
||||
<img
|
||||
:src="selectedImage.materialTempUrl"
|
||||
:alt="selectedImage.imageName"
|
||||
:src="selectedBaseImage.materialTempUrl"
|
||||
:alt="selectedBaseImage.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>
|
||||
<p><strong>{{ selectedBaseImage.imageName }}</strong></p>
|
||||
<p>{{ selectedBaseImage.ownerName }}</p>
|
||||
<p>{{ getImageTypeText(selectedBaseImage.imageType) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,7 +56,7 @@
|
||||
<!-- 参考图选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>参考图选择</h3>
|
||||
<h3>参考图选择 <span class="required-tag">(必选)</span></h3>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
@@ -65,6 +68,9 @@
|
||||
placeholder="请选择参考图"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleRefImageSearch"
|
||||
@change="handleRefImageChange"
|
||||
>
|
||||
<el-option
|
||||
@@ -109,7 +115,11 @@
|
||||
<!-- 前景边缘图1选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>前景边缘图1选择</h3>
|
||||
<h3>前景边缘图1选择 <span class="optional-tag">(可选)</span></h3>
|
||||
<div class="format-tip">
|
||||
<i class="el-icon-info" />
|
||||
<span>请选择支持透明通道的图片(PNG、GIF、WebP格式),此字段为可选项</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
@@ -121,6 +131,9 @@
|
||||
placeholder="请选择前景边缘图1"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleForegroundEdge1Search"
|
||||
@change="handleForegroundEdge1Change"
|
||||
>
|
||||
<el-option
|
||||
@@ -165,7 +178,11 @@
|
||||
<!-- 前景边缘图2选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>前景边缘图2选择</h3>
|
||||
<h3>前景边缘图2选择 <span class="optional-tag">(可选)</span></h3>
|
||||
<div class="format-tip">
|
||||
<i class="el-icon-info" />
|
||||
<span>请选择支持透明通道的图片(PNG、GIF、WebP格式),此字段为可选项</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
@@ -177,6 +194,9 @@
|
||||
placeholder="请选择前景边缘图2"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleForegroundEdge2Search"
|
||||
@change="handleForegroundEdge2Change"
|
||||
>
|
||||
<el-option
|
||||
@@ -221,7 +241,11 @@
|
||||
<!-- 背景边缘图选择区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>背景边缘图选择</h3>
|
||||
<h3>背景边缘图选择 <span class="optional-tag">(可选)</span></h3>
|
||||
<div class="format-tip">
|
||||
<i class="el-icon-info" />
|
||||
<span>此字段为可选项,可以选择也可以不选择</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<div class="two-column-layout">
|
||||
@@ -233,6 +257,9 @@
|
||||
placeholder="请选择背景边缘图"
|
||||
class="image-select"
|
||||
:loading="imageListLoading"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="handleBackgroundEdgeSearch"
|
||||
@change="handleBackgroundEdgeChange"
|
||||
>
|
||||
<el-option
|
||||
@@ -314,6 +341,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="parameter-row">
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">图片名称</label>
|
||||
<el-input
|
||||
v-model="form.imageName"
|
||||
placeholder="请输入图片名称"
|
||||
class="parameter-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="parameter-item">
|
||||
<label class="parameter-label">所有人姓名</label>
|
||||
<el-input
|
||||
@@ -378,6 +413,8 @@ export default {
|
||||
n: 1,
|
||||
refPromptWeight: 0.5,
|
||||
modelVersion: 'v3',
|
||||
// 图片信息
|
||||
imageName: '',
|
||||
// 所有人信息
|
||||
ownerName: '',
|
||||
ownerPhone: ''
|
||||
@@ -389,7 +426,23 @@ export default {
|
||||
selectedRefImage: null,
|
||||
selectedForegroundEdge1: null,
|
||||
selectedForegroundEdge2: null,
|
||||
selectedBackgroundEdge: null
|
||||
selectedBackgroundEdge: null,
|
||||
// 搜索关键词状态
|
||||
searchKeywords: {
|
||||
baseImage: '',
|
||||
refImage: '',
|
||||
foregroundEdge1: '',
|
||||
foregroundEdge2: '',
|
||||
backgroundEdge: ''
|
||||
},
|
||||
// 防抖定时器
|
||||
searchTimeouts: {
|
||||
baseImage: null,
|
||||
refImage: null,
|
||||
foregroundEdge1: null,
|
||||
foregroundEdge2: null,
|
||||
backgroundEdge: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -411,13 +464,26 @@ export default {
|
||||
},
|
||||
|
||||
// 加载图像列表
|
||||
loadImageList() {
|
||||
loadImageList(searchKeyword = '') {
|
||||
this.imageListLoading = true
|
||||
const params = {
|
||||
current: 1,
|
||||
size: 20
|
||||
size: 30,
|
||||
imageType: 'material' // 只显示素材类型的图片
|
||||
}
|
||||
|
||||
// 如果有搜索关键词,添加到参数中
|
||||
if (searchKeyword && searchKeyword.trim()) {
|
||||
params.imageName = searchKeyword.trim()
|
||||
}
|
||||
|
||||
console.log('发送到后端的搜索参数:', params)
|
||||
console.log('参数详情:', {
|
||||
imageType: params.imageType,
|
||||
imageName: params.imageName,
|
||||
current: params.current,
|
||||
size: params.size
|
||||
})
|
||||
getImageList(params).then(response => {
|
||||
console.log('图像列表响应:', response)
|
||||
console.log('响应数据结构:', {
|
||||
@@ -454,6 +520,22 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
// 主图搜索方法
|
||||
handleBaseImageSearch(query) {
|
||||
console.log('主图搜索关键词:', query)
|
||||
this.searchKeywords.baseImage = query
|
||||
|
||||
// 清除之前的定时器
|
||||
if (this.searchTimeouts.baseImage) {
|
||||
clearTimeout(this.searchTimeouts.baseImage)
|
||||
}
|
||||
|
||||
// 设置防抖,500ms后执行搜索
|
||||
this.searchTimeouts.baseImage = setTimeout(() => {
|
||||
this.loadImageList(query)
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 处理主图选择变化
|
||||
handleBaseImageChange(imageId) {
|
||||
console.log('选择的主图ID:', imageId)
|
||||
@@ -465,6 +547,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 参考图搜索方法
|
||||
handleRefImageSearch(query) {
|
||||
console.log('参考图搜索关键词:', query)
|
||||
this.searchKeywords.refImage = query
|
||||
|
||||
// 清除之前的定时器
|
||||
if (this.searchTimeouts.refImage) {
|
||||
clearTimeout(this.searchTimeouts.refImage)
|
||||
}
|
||||
|
||||
// 设置防抖,500ms后执行搜索
|
||||
this.searchTimeouts.refImage = setTimeout(() => {
|
||||
this.loadImageList(query)
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 处理参考图选择变化
|
||||
handleRefImageChange(refImageId) {
|
||||
console.log('选择的参考图ID:', refImageId)
|
||||
@@ -476,6 +574,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 前景边缘图1搜索方法
|
||||
handleForegroundEdge1Search(query) {
|
||||
console.log('前景边缘图1搜索关键词:', query)
|
||||
this.searchKeywords.foregroundEdge1 = query
|
||||
|
||||
// 清除之前的定时器
|
||||
if (this.searchTimeouts.foregroundEdge1) {
|
||||
clearTimeout(this.searchTimeouts.foregroundEdge1)
|
||||
}
|
||||
|
||||
// 设置防抖,500ms后执行搜索
|
||||
this.searchTimeouts.foregroundEdge1 = setTimeout(() => {
|
||||
this.loadImageList(query)
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 处理前景边缘图1选择变化
|
||||
handleForegroundEdge1Change(edge1Id) {
|
||||
console.log('选择的前景边缘图1 ID:', edge1Id)
|
||||
@@ -487,6 +601,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 前景边缘图2搜索方法
|
||||
handleForegroundEdge2Search(query) {
|
||||
console.log('前景边缘图2搜索关键词:', query)
|
||||
this.searchKeywords.foregroundEdge2 = query
|
||||
|
||||
// 清除之前的定时器
|
||||
if (this.searchTimeouts.foregroundEdge2) {
|
||||
clearTimeout(this.searchTimeouts.foregroundEdge2)
|
||||
}
|
||||
|
||||
// 设置防抖,500ms后执行搜索
|
||||
this.searchTimeouts.foregroundEdge2 = setTimeout(() => {
|
||||
this.loadImageList(query)
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 处理前景边缘图2选择变化
|
||||
handleForegroundEdge2Change(edge2Id) {
|
||||
console.log('选择的前景边缘图2 ID:', edge2Id)
|
||||
@@ -498,6 +628,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 背景边缘图搜索方法
|
||||
handleBackgroundEdgeSearch(query) {
|
||||
console.log('背景边缘图搜索关键词:', query)
|
||||
this.searchKeywords.backgroundEdge = query
|
||||
|
||||
// 清除之前的定时器
|
||||
if (this.searchTimeouts.backgroundEdge) {
|
||||
clearTimeout(this.searchTimeouts.backgroundEdge)
|
||||
}
|
||||
|
||||
// 设置防抖,500ms后执行搜索
|
||||
this.searchTimeouts.backgroundEdge = setTimeout(() => {
|
||||
this.loadImageList(query)
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 处理背景边缘图选择变化
|
||||
handleBackgroundEdgeChange(backgroundEdgeId) {
|
||||
console.log('选择的背景边缘图ID:', backgroundEdgeId)
|
||||
@@ -522,14 +668,66 @@ export default {
|
||||
person: '人物图',
|
||||
product: '产品图',
|
||||
material: '素材图',
|
||||
result: '成品',
|
||||
other: '其他'
|
||||
}
|
||||
return typeMap[type] || '未知'
|
||||
},
|
||||
|
||||
// 验证图片格式
|
||||
validateImageFormat(image, imageName) {
|
||||
// 检查图片URL是否包含透明通道信息
|
||||
const url = image.materialTempUrl
|
||||
if (!url) {
|
||||
return { valid: false, message: `${imageName}图片URL无效` }
|
||||
}
|
||||
|
||||
console.log(`验证${imageName}格式:`, {
|
||||
url: url,
|
||||
imageName: image.imageName,
|
||||
imageType: image.imageType
|
||||
})
|
||||
|
||||
// 检查文件扩展名 - 需要先去除URL参数
|
||||
const urlWithoutParams = url.split('?')[0] // 去除问号后的签名信息
|
||||
const extension = urlWithoutParams.split('.').pop().toLowerCase()
|
||||
const supportedFormats = ['png', 'gif', 'webp', 'jpg', 'jpeg']
|
||||
|
||||
console.log(`原始URL:${url}`)
|
||||
console.log(`去除参数后的URL:${urlWithoutParams}`)
|
||||
console.log(`文件扩展名:${extension}`)
|
||||
|
||||
// 对于前景边缘图,我们放宽格式要求,因为后端会处理格式转换
|
||||
// 主要检查是否是有效的图片格式
|
||||
if (!supportedFormats.includes(extension)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `${imageName}图片格式不支持,请使用常见的图片格式(PNG、JPG、GIF、WebP等)`
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是前景边缘图,给出建议但不强制要求特定格式
|
||||
if (imageName.includes('前景边缘图')) {
|
||||
console.log(`前景边缘图格式检查通过:${extension}`)
|
||||
|
||||
// 如果已经是PNG格式,不需要显示建议
|
||||
if (extension === 'png') {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
// 对于其他格式,给出建议但不阻止使用
|
||||
return {
|
||||
valid: true,
|
||||
message: `建议使用PNG格式以获得更好的透明通道支持,当前格式:${extension.toUpperCase()}`
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: true }
|
||||
},
|
||||
|
||||
// 处理生成按钮点击
|
||||
handleGenerate() {
|
||||
// 验证必填项
|
||||
// 验证必填项 - 只有主图和参考图是必选的
|
||||
if (!this.form.baseImageId) {
|
||||
this.$message.warning('请选择主图')
|
||||
return
|
||||
@@ -538,17 +736,44 @@ export default {
|
||||
this.$message.warning('请选择参考图')
|
||||
return
|
||||
}
|
||||
if (!this.form.foregroundEdge1Id) {
|
||||
this.$message.warning('请选择前景边缘图1')
|
||||
if (!this.form.imageName) {
|
||||
this.$message.warning('请输入图片名称')
|
||||
return
|
||||
}
|
||||
if (!this.form.foregroundEdge2Id) {
|
||||
this.$message.warning('请选择前景边缘图2')
|
||||
return
|
||||
// 其他图片都是可选的,不进行必填验证
|
||||
|
||||
// 验证已选择的图片格式(仅检查基本格式,不强制要求特定格式)
|
||||
// 前景边缘图1 - 可选
|
||||
if (this.form.foregroundEdge1Id && this.selectedForegroundEdge1) {
|
||||
const foregroundEdge1Validation = this.validateImageFormat(this.selectedForegroundEdge1, '前景边缘图1')
|
||||
if (!foregroundEdge1Validation.valid) {
|
||||
this.$message.error(foregroundEdge1Validation.message)
|
||||
return
|
||||
} else if (foregroundEdge1Validation.message) {
|
||||
console.log('前景边缘图1格式建议:', foregroundEdge1Validation.message)
|
||||
}
|
||||
}
|
||||
if (!this.form.backgroundEdgeId) {
|
||||
this.$message.warning('请选择背景边缘图')
|
||||
return
|
||||
|
||||
// 前景边缘图2 - 可选
|
||||
if (this.form.foregroundEdge2Id && this.selectedForegroundEdge2) {
|
||||
const foregroundEdge2Validation = this.validateImageFormat(this.selectedForegroundEdge2, '前景边缘图2')
|
||||
if (!foregroundEdge2Validation.valid) {
|
||||
this.$message.error(foregroundEdge2Validation.message)
|
||||
return
|
||||
} else if (foregroundEdge2Validation.message) {
|
||||
console.log('前景边缘图2格式建议:', foregroundEdge2Validation.message)
|
||||
}
|
||||
}
|
||||
|
||||
// 背景边缘图 - 可选
|
||||
if (this.form.backgroundEdgeId && this.selectedBackgroundEdge) {
|
||||
const backgroundEdgeValidation = this.validateImageFormat(this.selectedBackgroundEdge, '背景边缘图')
|
||||
if (!backgroundEdgeValidation.valid) {
|
||||
this.$message.error(backgroundEdgeValidation.message)
|
||||
return
|
||||
} else if (backgroundEdgeValidation.message) {
|
||||
console.log('背景边缘图格式建议:', backgroundEdgeValidation.message)
|
||||
}
|
||||
}
|
||||
|
||||
// 开始生成
|
||||
@@ -556,36 +781,61 @@ export default {
|
||||
|
||||
// 构建后端参数结构
|
||||
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
|
||||
baseImageUrl: this.selectedBaseImage.materialTempUrl,
|
||||
refImageUrl: this.selectedRefImage.materialTempUrl,
|
||||
refPrompt: this.form.refPrompt,
|
||||
imageName: this.form.imageName,
|
||||
ownerName: this.form.ownerName,
|
||||
ownerPhone: this.form.ownerPhone,
|
||||
referenceEdge: {
|
||||
foregroundEdge: [
|
||||
// 前景边缘图1 - 可选
|
||||
...(this.selectedForegroundEdge1 ? [this.selectedForegroundEdge1.materialTempUrl] : []),
|
||||
// 前景边缘图2 - 可选
|
||||
...(this.selectedForegroundEdge2 ? [this.selectedForegroundEdge2.materialTempUrl] : [])
|
||||
],
|
||||
background_edge: [
|
||||
this.selectedBackgroundEdge.materialTempUrl
|
||||
backgroundEdge: [
|
||||
// 背景边缘图 - 可选
|
||||
...(this.selectedBackgroundEdge ? [this.selectedBackgroundEdge.materialTempUrl] : [])
|
||||
],
|
||||
foreground_edge_prompt: [
|
||||
this.form.foregroundEdge1Prompt,
|
||||
this.form.foregroundEdge2Prompt
|
||||
foregroundEdgePrompt: [
|
||||
// 前景边缘图1提示词 - 可选,确保与foregroundEdge数组长度匹配
|
||||
...(this.selectedForegroundEdge1 ? [this.form.foregroundEdge1Prompt || ''] : []),
|
||||
// 前景边缘图2提示词 - 可选,确保与foregroundEdge数组长度匹配
|
||||
...(this.selectedForegroundEdge2 ? [this.form.foregroundEdge2Prompt || ''] : [])
|
||||
],
|
||||
background_edge_prompt: [
|
||||
this.form.backgroundEdgePrompt
|
||||
backgroundEdgePrompt: [
|
||||
// 背景边缘图提示词 - 可选
|
||||
...(this.selectedBackgroundEdge ? [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
|
||||
refPromptWeight: this.form.refPromptWeight,
|
||||
modelVersion: this.form.modelVersion
|
||||
}
|
||||
}
|
||||
|
||||
// 验证数组长度匹配
|
||||
const foregroundEdgeLength = requestData.referenceEdge.foregroundEdge.length
|
||||
const foregroundEdgePromptLength = requestData.referenceEdge.foregroundEdgePrompt.length
|
||||
|
||||
console.log('数组长度验证:', {
|
||||
foregroundEdge: foregroundEdgeLength,
|
||||
foregroundEdgePrompt: foregroundEdgePromptLength,
|
||||
isMatched: foregroundEdgeLength === foregroundEdgePromptLength
|
||||
})
|
||||
|
||||
if (foregroundEdgeLength !== foregroundEdgePromptLength) {
|
||||
console.error('数组长度不匹配!', {
|
||||
foregroundEdge: requestData.referenceEdge.foregroundEdge,
|
||||
foregroundEdgePrompt: requestData.referenceEdge.foregroundEdgePrompt
|
||||
})
|
||||
this.$message.error('前景边缘图和提示词数量不匹配,请检查输入')
|
||||
this.generateLoading = false
|
||||
return
|
||||
}
|
||||
|
||||
console.log('开始生成图像,参数:', requestData)
|
||||
|
||||
// 调用后端接口
|
||||
@@ -610,13 +860,38 @@ export default {
|
||||
console.log('请求ID:', response.requestId)
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response.message || '图像处理失败')
|
||||
// 处理特定的错误代码
|
||||
let errorMessage = response.message || '图像处理失败'
|
||||
|
||||
if (response.code === 'BadRequest.UnsupportedFileFormat') {
|
||||
errorMessage = '图片格式不支持:前景边缘图需要RGBA或LA模式的图片(支持透明通道的PNG、GIF或WebP格式)'
|
||||
} else if (response.code === 'BadRequest.InvalidImageFormat') {
|
||||
errorMessage = '图片格式无效,请检查图片文件是否损坏'
|
||||
} else if (response.code === 'BadRequest.ImageSizeExceeded') {
|
||||
errorMessage = '图片尺寸过大,请使用较小的图片'
|
||||
}
|
||||
|
||||
this.$message.error(errorMessage)
|
||||
console.error('图像处理失败:', response)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.generateLoading = false
|
||||
console.error('调用图像处理接口失败:', error)
|
||||
this.$message.error('调用图像处理接口失败:' + (error.message || '未知错误'))
|
||||
|
||||
// 处理网络错误或服务器错误
|
||||
let errorMessage = '调用图像处理接口失败'
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
if (errorData.code === 'BadRequest.UnsupportedFileFormat') {
|
||||
errorMessage = '图片格式不支持:前景边缘图需要RGBA或LA模式的图片(支持透明通道的PNG、GIF或WebP格式)'
|
||||
} else if (errorData.message) {
|
||||
errorMessage = errorData.message
|
||||
}
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message
|
||||
}
|
||||
|
||||
this.$message.error(errorMessage)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -627,7 +902,7 @@ export default {
|
||||
.app-container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.content {
|
||||
@@ -639,33 +914,67 @@ export default {
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 12px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 15px 20px;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
padding: 12px 16px;
|
||||
color: #495057;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.section-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.format-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.format-tip i {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.optional-tag {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
font-weight: normal;
|
||||
background: #f0f2f5;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.required-tag {
|
||||
font-size: 12px;
|
||||
color: #f56c6c;
|
||||
font-weight: normal;
|
||||
background: #fef0f0;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.section-content {
|
||||
padding: 20px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.two-column-layout {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
@@ -680,7 +989,7 @@ export default {
|
||||
}
|
||||
|
||||
.selector-wrapper {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.image-select {
|
||||
@@ -690,23 +999,23 @@ export default {
|
||||
.image-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 15px;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: #f8f9fa;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
height: 100px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #dcdfe6;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 6px;
|
||||
border: 1px solid #dcdfe6;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -735,7 +1044,7 @@ export default {
|
||||
}
|
||||
|
||||
.prompt-container {
|
||||
margin-top: 15px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.prompt-input {
|
||||
@@ -757,12 +1066,12 @@ export default {
|
||||
.parameter-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.parameter-row {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -787,23 +1096,23 @@ export default {
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.generate-button {
|
||||
padding: 12px 40px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 10px 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(135deg, #409eff 0%, #36a3f7 100%);
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.generate-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
|
||||
}
|
||||
|
||||
.generate-button:active {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<el-option label="人物图" value="person" />
|
||||
<el-option label="产品图" value="product" />
|
||||
<el-option label="素材图" value="material" />
|
||||
<el-option label="成品" value="result" />
|
||||
<el-option label="其他" value="other" />
|
||||
</el-select>
|
||||
<el-button
|
||||
@@ -70,6 +71,15 @@
|
||||
>
|
||||
上传素材
|
||||
</el-button>
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="warning"
|
||||
icon="el-icon-refresh"
|
||||
:loading="statusCheckLoading"
|
||||
@click="handleStatusCheck"
|
||||
>
|
||||
状态检查
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="multipleSelection.length > 0"
|
||||
class="filter-item"
|
||||
@@ -128,16 +138,35 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="素材图片" width="100" align="center">
|
||||
<el-table-column label="素材图片" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
v-if="scope.row.materialTempUrl"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="openMaterialUrl( scope.row.materialTempUrl)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<div v-if="scope.row.materialTempUrl">
|
||||
<!-- 如果是JSON串,显示下拉框 -->
|
||||
<el-select
|
||||
v-if="isJsonString(scope.row.materialTempUrl)"
|
||||
v-model="selectedMaterialUrl[scope.row.uuid]"
|
||||
placeholder="选择图片"
|
||||
size="small"
|
||||
style="width: 120px;"
|
||||
@change="handleMaterialUrlChange(scope.row.uuid, $event)"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in parseMaterialUrls(scope.row.materialTempUrl)"
|
||||
:key="index"
|
||||
:label="item.label || `图片${index + 1}`"
|
||||
:value="item.url || item"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 如果是单个URL,显示查看按钮 -->
|
||||
<el-button
|
||||
v-else
|
||||
type="text"
|
||||
size="small"
|
||||
@click="openMaterialUrl(scope.row.materialTempUrl)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -159,11 +188,6 @@
|
||||
<span>{{ scope.row.prompt || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="功能函数" min-width="120" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.functionName || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="放大倍数" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.scaleFactor || '-' }}</span>
|
||||
@@ -174,6 +198,16 @@
|
||||
<span>{{ formatDateTime(scope.row.updateTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="任务状态" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag
|
||||
:type="getTaskStatusTagType(scope.row.taskStatus)"
|
||||
size="small"
|
||||
>
|
||||
{{ getTaskStatusText(scope.row.taskStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="280" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
@@ -236,6 +270,73 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 素材信息对话框 -->
|
||||
<el-dialog
|
||||
title="素材信息"
|
||||
:visible.sync="materialDialogVisible"
|
||||
width="60%"
|
||||
center
|
||||
>
|
||||
<div v-if="isJsonString(currentMaterialData)">
|
||||
<div style="border: 1px solid #e4e7ed; border-radius: 6px; padding: 16px; background: #f8f9fa;">
|
||||
<!-- 图像信息 -->
|
||||
<div style="margin-bottom: 16px;">
|
||||
<h4 style="margin: 0 0 12px 0; color: #303133; font-size: 14px; font-weight: 600;">图像信息</h4>
|
||||
<div v-if="getMaterialData(currentMaterialData).baseImageUrl" style="margin-bottom: 8px;">
|
||||
<div style="font-weight: 500; color: #606266;">基础图像 (baseImageUrl):</div>
|
||||
<div style="margin-left: 16px;">
|
||||
<div style="font-weight: 500; color: #606266;">地址: </div>
|
||||
<el-button type="text" size="small" style="padding: 0; color: #409eff; text-decoration: underline;" @click="openMaterialUrl(getMaterialData(currentMaterialData).baseImageUrl)">
|
||||
链接
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="getMaterialData(currentMaterialData).refImageUrl" style="margin-bottom: 8px;">
|
||||
<div style="font-weight: 500; color: #606266;">参考图像 (refImageUrl):</div>
|
||||
<div style="margin-left: 16px;">
|
||||
<div style="font-weight: 500; color: #606266;">地址: </div>
|
||||
<el-button type="text" size="small" style="padding: 0; color: #409eff; text-decoration: underline;" @click="openMaterialUrl(getMaterialData(currentMaterialData).refImageUrl)">
|
||||
链接
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 边缘信息 -->
|
||||
<div v-if="getMaterialData(currentMaterialData).referenceEdge">
|
||||
<h4 style="margin: 0 0 12px 0; color: #303133; font-size: 14px; font-weight: 600;">边缘信息 (referenceEdge)</h4>
|
||||
<!-- 背景边缘图片 -->
|
||||
<div v-if="getMaterialData(currentMaterialData).referenceEdge.backgroundEdge" style="margin-bottom: 8px;">
|
||||
<div style="font-weight: 500; color: #606266;">背景边缘图片 (backgroundEdge):</div>
|
||||
<div v-for="(url, index) in getMaterialData(currentMaterialData).referenceEdge.backgroundEdge" :key="index" style="margin-left: 16px;">
|
||||
<div style="font-weight: 500; color: #606266;">地址: </div>
|
||||
<el-button type="text" size="small" style="padding: 0; color: #409eff; text-decoration: underline;" @click="openMaterialUrl(url)">
|
||||
链接
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 前景边缘图片 -->
|
||||
<div v-if="getMaterialData(currentMaterialData).referenceEdge.foregroundEdge" style="margin-bottom: 8px;">
|
||||
<div style="font-weight: 500; color: #606266;">前景边缘图片 (foregroundEdge):</div>
|
||||
<div v-for="(url, index) in getMaterialData(currentMaterialData).referenceEdge.foregroundEdge" :key="index" style="margin-left: 16px;">
|
||||
<div style="font-weight: 500; color: #606266;">地址{{ index + 1 }}: </div>
|
||||
<el-button type="text" size="small" style="padding: 0; color: #409eff; text-decoration: underline;" @click="openMaterialUrl(url)">
|
||||
链接
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-input v-model="currentMaterialData" placeholder="素材URL" readonly />
|
||||
<el-button v-if="currentMaterialData" type="text" size="small" style="margin-top: 5px;" @click="openMaterialUrl(currentMaterialData)">
|
||||
查看素材图片
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<el-dialog
|
||||
:title="dialogTitle"
|
||||
@@ -283,6 +384,7 @@
|
||||
<el-option label="人物图" value="person" />
|
||||
<el-option label="产品图" value="product" />
|
||||
<el-option label="素材图" value="material" />
|
||||
<el-option label="成品" value="result" />
|
||||
<el-option label="其他" value="other" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -300,7 +402,10 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="素材URL">
|
||||
<el-input v-model="temp.materialUrl" placeholder="请输入素材URL" />
|
||||
<el-input v-model="temp.materialTempUrl" placeholder="素材URL" readonly />
|
||||
<el-button v-if="temp.materialTempUrl" type="text" size="small" style="margin-top: 5px;" @click="openMaterialUrl(temp.materialTempUrl)">
|
||||
查看素材图片
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="成品图片URL">
|
||||
<el-input v-model="temp.resultImageUrl" placeholder="请输入成品图片URL" />
|
||||
@@ -406,6 +511,7 @@ export default {
|
||||
imageType: undefined
|
||||
},
|
||||
multipleSelection: [],
|
||||
selectedMaterialUrl: {}, // 存储每行选中的素材URL
|
||||
temp: {
|
||||
id: undefined,
|
||||
imageName: '',
|
||||
@@ -426,10 +532,14 @@ export default {
|
||||
dialogTitle: '',
|
||||
previewDialogVisible: false,
|
||||
previewImageUrl: '',
|
||||
materialDialogVisible: false,
|
||||
currentMaterialData: '',
|
||||
// 上传素材相关
|
||||
uploadDialogVisible: false,
|
||||
uploadLoading: false,
|
||||
fileList: [],
|
||||
// 状态检查相关
|
||||
statusCheckLoading: false,
|
||||
uploadForm: {
|
||||
imageName: '',
|
||||
ownerName: '',
|
||||
@@ -527,6 +637,13 @@ export default {
|
||||
},
|
||||
handleView(row) {
|
||||
this.temp = Object.assign({}, row)
|
||||
// 确保素材URL字段正确复制
|
||||
if (row.materialTempUrl && !this.temp.materialTempUrl) {
|
||||
this.temp.materialTempUrl = row.materialTempUrl
|
||||
}
|
||||
if (row.materialUrl && !this.temp.materialUrl) {
|
||||
this.temp.materialUrl = row.materialUrl
|
||||
}
|
||||
this.dialogStatus = 'view'
|
||||
this.dialogTitle = '查看图像详情'
|
||||
this.dialogVisible = true
|
||||
@@ -678,12 +795,102 @@ export default {
|
||||
this.$message.warning('素材图片URL不存在')
|
||||
}
|
||||
},
|
||||
// 检查字符串是否为JSON格式
|
||||
isJsonString(str) {
|
||||
if (!str || typeof str !== 'string') {
|
||||
console.log('isJsonString: 不是字符串或为空', str)
|
||||
return false
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(str)
|
||||
const isObject = typeof parsed === 'object' && parsed !== null
|
||||
const hasContent = Array.isArray(parsed) ? parsed.length > 0 : Object.keys(parsed).length > 0
|
||||
const result = isObject && hasContent
|
||||
|
||||
console.log('isJsonString 判断结果:', {
|
||||
str: str.substring(0, 100) + '...',
|
||||
isObject,
|
||||
hasContent,
|
||||
result,
|
||||
parsed: parsed
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (e) {
|
||||
console.log('isJsonString: JSON解析失败', e.message)
|
||||
return false
|
||||
}
|
||||
},
|
||||
// 解析素材URL的JSON串
|
||||
parseMaterialUrls(jsonStr) {
|
||||
try {
|
||||
const data = JSON.parse(jsonStr)
|
||||
const urls = []
|
||||
|
||||
// 如果是数组,直接返回
|
||||
if (Array.isArray(data)) {
|
||||
return data
|
||||
}
|
||||
|
||||
// 如果是对象,提取所有URL字段
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
// 提取基础图片URL
|
||||
if (data.baseImageUrl) {
|
||||
urls.push({ label: '基础图片', url: data.baseImageUrl })
|
||||
}
|
||||
if (data.refImageUrl) {
|
||||
urls.push({ label: '参考图片', url: data.refImageUrl })
|
||||
}
|
||||
|
||||
// 提取参考边缘图片
|
||||
if (data.referenceEdge) {
|
||||
if (data.referenceEdge.foregroundEdge && Array.isArray(data.referenceEdge.foregroundEdge)) {
|
||||
data.referenceEdge.foregroundEdge.forEach((url, index) => {
|
||||
urls.push({ label: `前景边缘图${index + 1}`, url })
|
||||
})
|
||||
}
|
||||
if (data.referenceEdge.backgroundEdge && Array.isArray(data.referenceEdge.backgroundEdge)) {
|
||||
data.referenceEdge.backgroundEdge.forEach((url, index) => {
|
||||
urls.push({ label: `背景边缘图${index + 1}`, url })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return urls
|
||||
} catch (e) {
|
||||
console.error('解析素材URL JSON失败:', e)
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 处理素材URL下拉框选择变化
|
||||
handleMaterialUrlChange(uuid, selectedUrl) {
|
||||
console.log('选择素材URL:', { uuid, selectedUrl })
|
||||
if (selectedUrl) {
|
||||
this.openMaterialUrl(selectedUrl)
|
||||
}
|
||||
},
|
||||
// 获取素材数据的解析结果
|
||||
getMaterialData(jsonStr) {
|
||||
try {
|
||||
return JSON.parse(jsonStr)
|
||||
} catch (e) {
|
||||
console.error('解析素材数据失败:', e)
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 打开素材信息对话框
|
||||
openMaterialDialog(materialData) {
|
||||
this.currentMaterialData = materialData
|
||||
this.materialDialogVisible = true
|
||||
},
|
||||
getImageTypeTag(type) {
|
||||
const typeMap = {
|
||||
background: 'success',
|
||||
person: 'primary',
|
||||
product: 'warning',
|
||||
material: 'danger',
|
||||
result: 'success',
|
||||
other: 'info'
|
||||
}
|
||||
return typeMap[type] || 'info'
|
||||
@@ -694,10 +901,31 @@ export default {
|
||||
person: '人物图',
|
||||
product: '产品图',
|
||||
material: '素材图',
|
||||
result: '成品',
|
||||
other: '其他'
|
||||
}
|
||||
return typeMap[type] || '未知'
|
||||
},
|
||||
// 获取任务状态文本
|
||||
getTaskStatusText(status) {
|
||||
const statusMap = {
|
||||
PENDING: '待处理',
|
||||
RUNNING: '运行中',
|
||||
SUCCEEDED: '成功',
|
||||
FAILED: '失败'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
},
|
||||
// 获取任务状态标签类型
|
||||
getTaskStatusTagType(status) {
|
||||
const typeMap = {
|
||||
PENDING: 'warning',
|
||||
RUNNING: 'primary',
|
||||
SUCCEEDED: 'success',
|
||||
FAILED: 'danger'
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
},
|
||||
// 格式化日期时间
|
||||
formatDateTime(dateTime) {
|
||||
if (!dateTime) {
|
||||
@@ -724,6 +952,79 @@ export default {
|
||||
this.$refs['uploadForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
// 状态检查方法
|
||||
handleStatusCheck() {
|
||||
this.statusCheckLoading = true
|
||||
console.log('开始执行状态检查...')
|
||||
|
||||
// 导入API方法
|
||||
import('@/api/image-management').then(({ checkImageModelStatus }) => {
|
||||
checkImageModelStatus().then(response => {
|
||||
console.log('状态检查响应:', response)
|
||||
this.statusCheckLoading = false
|
||||
|
||||
if (response.success) {
|
||||
this.$message.success(response.message || '状态检查执行成功')
|
||||
// 刷新列表以获取最新状态
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.message || '状态检查执行失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('状态检查失败:', error)
|
||||
this.statusCheckLoading = false
|
||||
this.$message.error('状态检查失败: ' + (error.message || '未知错误'))
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error('导入API失败:', error)
|
||||
this.statusCheckLoading = false
|
||||
this.$message.error('导入API失败')
|
||||
})
|
||||
},
|
||||
// 图像格式转换方法
|
||||
convertImageToRGBA(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
const img = new Image()
|
||||
|
||||
img.onload = () => {
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
|
||||
// 绘制图像到canvas
|
||||
ctx.drawImage(img, 0, 0)
|
||||
|
||||
// 获取RGBA数据
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
||||
|
||||
// 确保所有像素都有Alpha通道
|
||||
for (let i = 3; i < imageData.data.length; i += 4) {
|
||||
if (imageData.data[i] === 0) {
|
||||
imageData.data[i] = 255 // 设置不透明
|
||||
}
|
||||
}
|
||||
|
||||
// 将修改后的数据绘制回canvas
|
||||
ctx.putImageData(imageData, 0, 0)
|
||||
|
||||
// 转换为Blob
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) {
|
||||
resolve(blob)
|
||||
} else {
|
||||
reject(new Error('图像转换失败'))
|
||||
}
|
||||
}, 'image/png') // PNG格式支持RGBA
|
||||
}
|
||||
|
||||
img.onerror = () => {
|
||||
reject(new Error('图像加载失败'))
|
||||
}
|
||||
|
||||
img.src = URL.createObjectURL(file)
|
||||
})
|
||||
},
|
||||
resetUploadForm() {
|
||||
this.uploadForm = {
|
||||
imageName: '',
|
||||
@@ -771,40 +1072,60 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
uploadMaterial() {
|
||||
// 创建FormData对象
|
||||
const formData = new FormData()
|
||||
formData.append('file', this.uploadForm.file)
|
||||
// 注意:imageName, ownerName, ownerPhone 作为查询参数传递,而不是FormData
|
||||
async uploadMaterial() {
|
||||
try {
|
||||
// 检查文件类型
|
||||
const file = this.uploadForm.file
|
||||
if (!file.type.startsWith('image/')) {
|
||||
this.$message.error('请选择图像文件')
|
||||
this.uploadLoading = false
|
||||
return
|
||||
}
|
||||
|
||||
// 准备查询参数
|
||||
const params = {
|
||||
imageName: this.uploadForm.imageName,
|
||||
ownerName: this.uploadForm.ownerName,
|
||||
ownerPhone: this.uploadForm.ownerPhone
|
||||
console.log('开始转换图像格式...')
|
||||
|
||||
// 转换图像为RGBA格式
|
||||
const convertedFile = await this.convertImageToRGBA(file)
|
||||
console.log('图像格式转换完成')
|
||||
|
||||
// 创建FormData对象
|
||||
const formData = new FormData()
|
||||
formData.append('file', convertedFile, file.name) // 使用转换后的文件
|
||||
// 注意:imageName, ownerName, ownerPhone 作为查询参数传递,而不是FormData
|
||||
|
||||
// 准备查询参数
|
||||
const params = {
|
||||
imageName: this.uploadForm.imageName,
|
||||
ownerName: this.uploadForm.ownerName,
|
||||
ownerPhone: this.uploadForm.ownerPhone
|
||||
}
|
||||
|
||||
console.log('上传数据:', {
|
||||
imageName: this.uploadForm.imageName,
|
||||
ownerName: this.uploadForm.ownerName,
|
||||
ownerPhone: this.uploadForm.ownerPhone,
|
||||
fileName: file.name,
|
||||
fileSize: file.size
|
||||
})
|
||||
|
||||
// 调用真实的上传API,传递查询参数
|
||||
uploadMaterial(formData, params).then(response => {
|
||||
console.log('上传响应:', response)
|
||||
this.uploadLoading = false
|
||||
this.uploadDialogVisible = false
|
||||
this.$message.success('素材上传成功')
|
||||
this.getList() // 刷新列表
|
||||
this.resetUploadForm()
|
||||
}).catch(error => {
|
||||
console.error('上传失败:', error)
|
||||
this.uploadLoading = false
|
||||
this.$message.error('上传失败: ' + (error.message || '未知错误'))
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('图像格式转换失败:', error)
|
||||
this.uploadLoading = false
|
||||
this.$message.error('图像格式转换失败: ' + (error.message || '未知错误'))
|
||||
}
|
||||
|
||||
console.log('上传数据:', {
|
||||
imageName: this.uploadForm.imageName,
|
||||
ownerName: this.uploadForm.ownerName,
|
||||
ownerPhone: this.uploadForm.ownerPhone,
|
||||
fileName: this.uploadForm.file.name,
|
||||
fileSize: this.uploadForm.file.size
|
||||
})
|
||||
|
||||
// 调用真实的上传API,传递查询参数
|
||||
uploadMaterial(formData, params).then(response => {
|
||||
console.log('上传响应:', response)
|
||||
this.uploadLoading = false
|
||||
this.uploadDialogVisible = false
|
||||
this.$message.success('素材上传成功')
|
||||
this.getList() // 刷新列表
|
||||
this.resetUploadForm()
|
||||
}).catch(error => {
|
||||
console.error('上传失败:', error)
|
||||
this.uploadLoading = false
|
||||
this.$message.error('上传失败: ' + (error.message || '未知错误'))
|
||||
})
|
||||
},
|
||||
// 去除水印处理方法
|
||||
handleRemoveWatermark(row) {
|
||||
|
||||
Reference in New Issue
Block a user