feat(ai): 支持双模型多视角AI设计生图与后台管理系统
- 实现AI多视角设计图生成功能,支持6个可选设计参数配置 - 集成SiliconFlow FLUX.1与火山引擎Seedream 4.5双模型切换 - 构建专业中文转英文prompt系统,提升AI生成质量 - 前端设计预览支持多视角切换与视角指示器展示 - 增加多视角设计图片DesignImage模型关联及存储 - 后端设计服务异步调用AI接口,失败时降级生成mock图 - 新增管理员后台管理路由及完整的权限校验机制 - 实现后台模块:仪表盘、系统配置、用户/品类/设计管理 - 配置数据库系统配置表,支持动态AI配置及热更新 - 增加用户管理员标识字段,管理后台登录鉴权支持 - 更新API接口支持多视角设计参数及后台管理接口 - 优化设计删除逻辑,删除多视角相关图片文件 - 前端新增管理后台页面与路由,布局样式独立分离 - 更新环境变量增加AI模型相关Key与参数配置说明 - 引入httpx异步HTTP客户端用于AI接口调用及图片下载 - README文档完善AI多视角生图与后台管理详细功能与流程说明
This commit is contained in:
@@ -1,14 +1,27 @@
|
||||
<template>
|
||||
<div class="design-preview">
|
||||
<!-- 视角 Tab 栏(多图时显示) -->
|
||||
<div class="view-tabs" v-if="hasMultipleViews">
|
||||
<button
|
||||
v-for="(img, idx) in design.images"
|
||||
:key="img.id"
|
||||
class="view-tab"
|
||||
:class="{ active: activeViewIndex === idx }"
|
||||
@click="activeViewIndex = idx"
|
||||
>
|
||||
{{ img.view_name }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 图片预览区 -->
|
||||
<div class="preview-container">
|
||||
<div class="image-wrapper" :style="{ transform: `scale(${scale})` }">
|
||||
<el-image
|
||||
:src="imageUrl"
|
||||
:src="currentImageUrl"
|
||||
:alt="design.prompt"
|
||||
fit="contain"
|
||||
:preview-src-list="[imageUrl]"
|
||||
:initial-index="0"
|
||||
:preview-src-list="allImageUrls"
|
||||
:initial-index="activeViewIndex"
|
||||
preview-teleported
|
||||
class="design-image"
|
||||
>
|
||||
@@ -27,6 +40,11 @@
|
||||
</el-image>
|
||||
</div>
|
||||
|
||||
<!-- 视角指示器(多图时显示) -->
|
||||
<div class="view-indicator" v-if="hasMultipleViews">
|
||||
<span class="indicator-text">{{ activeViewName }} ({{ activeViewIndex + 1 }}/{{ design.images.length }})</span>
|
||||
</div>
|
||||
|
||||
<!-- 缩放控制 -->
|
||||
<div class="zoom-controls">
|
||||
<button class="zoom-btn" @click="zoomOut" :disabled="scale <= 0.5">
|
||||
@@ -84,7 +102,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Loading, PictureFilled, ZoomIn, ZoomOut, RefreshRight, Download, User } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
@@ -97,17 +115,48 @@ const props = defineProps<{
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 当前视角索引
|
||||
const activeViewIndex = ref(0)
|
||||
|
||||
// 缩放比例
|
||||
const scale = ref(1)
|
||||
|
||||
// 图片URL(添加API前缀)
|
||||
const imageUrl = computed(() => {
|
||||
if (!props.design.image_url) return ''
|
||||
// 如果已经是完整URL则直接使用,否则添加 /api 前缀
|
||||
if (props.design.image_url.startsWith('http')) {
|
||||
return props.design.image_url
|
||||
// 是否有多视角图片
|
||||
const hasMultipleViews = computed(() => {
|
||||
return props.design.images && props.design.images.length > 1
|
||||
})
|
||||
|
||||
// 当前视角名称
|
||||
const activeViewName = computed(() => {
|
||||
if (props.design.images && props.design.images.length > 0) {
|
||||
return props.design.images[activeViewIndex.value]?.view_name || ''
|
||||
}
|
||||
return `/api${props.design.image_url}`
|
||||
return ''
|
||||
})
|
||||
|
||||
// 获取图片URL(添加API前缀)
|
||||
const toImageUrl = (url: string | null): string => {
|
||||
if (!url) return ''
|
||||
if (url.startsWith('http')) return url
|
||||
return `/api${url}`
|
||||
}
|
||||
|
||||
// 当前显示的图片URL
|
||||
const currentImageUrl = computed(() => {
|
||||
// 优先用多视角图片
|
||||
if (props.design.images && props.design.images.length > 0) {
|
||||
return toImageUrl(props.design.images[activeViewIndex.value]?.image_url)
|
||||
}
|
||||
// 兼容旧数据,使用单图
|
||||
return toImageUrl(props.design.image_url)
|
||||
})
|
||||
|
||||
// 所有图片URL(用于大图预览)
|
||||
const allImageUrls = computed(() => {
|
||||
if (props.design.images && props.design.images.length > 0) {
|
||||
return props.design.images.map(img => toImageUrl(img.image_url))
|
||||
}
|
||||
return [toImageUrl(props.design.image_url)]
|
||||
})
|
||||
|
||||
// 下载URL
|
||||
@@ -117,7 +166,13 @@ const downloadUrl = computed(() => getDesignDownloadUrl(props.design.id))
|
||||
const downloadFilename = computed(() => {
|
||||
const category = props.design.category?.name || '设计'
|
||||
const subType = props.design.sub_type?.name || ''
|
||||
return `${category}${subType ? '-' + subType : ''}-${props.design.id}.png`
|
||||
const viewSuffix = hasMultipleViews.value ? `-${activeViewName.value}` : ''
|
||||
return `${category}${subType ? '-' + subType : ''}${viewSuffix}-${props.design.id}.png`
|
||||
})
|
||||
|
||||
// 切换视角时重置缩放
|
||||
watch(activeViewIndex, () => {
|
||||
scale.value = 1
|
||||
})
|
||||
|
||||
// 放大
|
||||
@@ -163,6 +218,54 @@ $text-light: #999999;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.view-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.view-tab {
|
||||
flex: 1;
|
||||
padding: 10px 16px;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
color: $text-secondary;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
letter-spacing: 1px;
|
||||
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
background: rgba($primary-color, 0.05);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $primary-color;
|
||||
color: #fff;
|
||||
border-color: $primary-color;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.view-indicator {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.indicator-text {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
|
||||
Reference in New Issue
Block a user