refactor parameters for JimengCreate page

This commit is contained in:
GeekMaster
2025-09-11 15:48:07 +08:00
parent 896b5de0a4
commit 65fb58585c
58 changed files with 716 additions and 1174 deletions

View File

@@ -5,17 +5,16 @@
<!-- 功能分类按钮组 -->
<div class="category-buttons">
<div class="category-grid">
<div
v-for="category in store.categories"
:key="category.key"
:class="['category-btn', { active: store.activeCategory === category.key }]"
@click="store.switchCategory(category.key)"
<button
v-for="f in store.functions"
:key="f.key"
class="category-btn text-base"
:class="{ active: store.activeFunction === f.key }"
@click="store.switchFunction(f)"
>
<div class="category-icon">
<i :class="getCategoryIcon(category.key)"></i>
</div>
<div class="category-name">{{ category.name }}</div>
</div>
<i class="iconfont mr-2 !text-xl" :class="f.icon"></i>
{{ f.name }}
</button>
</div>
</div>
@@ -139,290 +138,17 @@
</div>
<!-- 功能开关 -->
<div
class="function-switch"
v-if="
store.activeCategory === 'image_generation' || store.activeCategory === 'video_generation'
"
>
<div class="switch-label">
<el-icon><Switch /></el-icon>
生成模式
</div>
<div class="switch-container">
<div class="switch-info">
<div class="switch-title">
{{ store.activeCategory === 'image_generation' ? '图生图人像写真' : '图生视频' }}
</div>
</div>
<el-switch v-model="store.useImageInput" @change="store.switchInputMode" />
</div>
</div>
<!-- 参数容器 -->
<div class="params-container">
<!-- 文生图 -->
<div v-if="store.activeFunction === 'text_to_image'" class="function-panel">
<div class="param-line pt">
<span class="label">提示词:</span>
</div>
<div class="param-line">
<el-input
v-model="store.currentPrompt"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
placeholder="请输入图片描述,越详细越好"
maxlength="2000"
show-word-limit
/>
</div>
<div class="param-line pt">
<span class="label">图片尺寸:</span>
</div>
<div class="param-line">
<el-select v-model="store.textToImageParams.size" placeholder="选择尺寸">
<el-option
v-for="opt in imageSizeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</div>
<div class="param-line">
<span class="label"
>创意度
<el-tooltip content="创意度越高,影响文本描述的程度越高" placement="top">
<i class="iconfont icon-info cursor-pointer ml-1"></i> </el-tooltip
></span>
</div>
<div class="item-group">
<el-slider v-model="store.textToImageParams.scale" :min="1" :max="10" :step="0.5" />
</div>
<div class="item-group flex justify-between">
<span class="label">智能优化提示词</span>
<el-switch v-model="store.textToImageParams.use_pre_llm" />
</div>
</div>
<!-- 图生图 -->
<div v-if="store.activeFunction === 'image_to_image'" class="function-panel">
<div class="param-line pt">
<span class="label">上传图片:</span>
</div>
<div class="param-line">
<ImageUpload
v-model="store.imageToImageParams.image_input"
:max-count="1"
:multiple="false"
/>
</div>
<div class="param-line pt">
<span class="label">提示词:</span>
</div>
<div class="param-line">
<el-input
v-model="store.currentPrompt"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
placeholder="描述你想要的图片效果"
maxlength="2000"
show-word-limit
/>
</div>
<div class="param-line pt">
<span class="label">图片尺寸:</span>
</div>
<div class="param-line">
<el-select v-model="store.imageToImageParams.size" placeholder="选择尺寸">
<el-option
v-for="opt in imageSizeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</div>
</div>
<!-- 图像编辑 -->
<div v-if="store.activeFunction === 'image_edit'" class="function-panel">
<div class="param-line pt">
<span class="label">上传图片:</span>
</div>
<div class="param-line">
<ImageUpload
v-model="store.imageEditParams.image_input"
:max-count="1"
:multiple="false"
/>
</div>
<div class="param-line pt">
<span class="label">编辑提示词:</span>
</div>
<div class="param-line">
<el-input
v-model="store.currentPrompt"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
placeholder="描述你想要的编辑效果"
maxlength="2000"
show-word-limit
/>
</div>
<div class="item-group">
<span class="label">编辑强度:</span>
<el-slider v-model="store.imageEditParams.scale" :min="0" :max="1" :step="0.1" />
</div>
</div>
<!-- 图像特效 -->
<div v-if="store.activeFunction === 'image_effects'" class="function-panel">
<div class="param-line pt">
<span class="label">上传图片:</span>
</div>
<div class="param-line">
<ImageUpload
v-model="store.imageEffectsParams.image_input"
:max-count="1"
:multiple="false"
/>
</div>
<div class="param-line pt">
<span class="label">特效模板:</span>
</div>
<div class="param-line">
<el-select
v-model="store.imageEffectsParams.template_id"
placeholder="选择特效模板"
popper-class="jimeng-template-select"
@change="handleTemplateChange($event)"
>
<template #prefix>
<div class="flex items-center py-1">
<el-image
v-if="templatePreview"
:src="templatePreview"
class="w-[50px] h-[50px] object-cover rounded-md"
:preview-src-list="[templatePreview]"
:preview-teleported="true"
@click.stop
/>
</div>
</template>
<el-option
v-for="opt in imageEffectsTemplateOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
>
<div class="flex flex-row justify-between">
<span class="template-label">{{ opt.label }}</span>
<img
v-if="opt.preview"
:src="opt.preview"
:alt="opt.label"
class="w-[50px] h-[50px] object-cover rounded-md"
/>
</div>
</el-option>
</el-select>
</div>
<div class="param-line pt">
<span class="label">输出尺寸:</span>
</div>
<div class="param-line">
<el-select v-model="store.imageEffectsParams.size" placeholder="选择尺寸">
<el-option
v-for="opt in imageSizeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</div>
</div>
<!-- 文生视频 -->
<div v-if="store.activeFunction === 'text_to_video'" class="function-panel">
<div class="param-line pt">
<span class="label">提示词:</span>
</div>
<div class="param-line">
<el-input
v-model="store.currentPrompt"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
placeholder="描述你想要的视频内容"
maxlength="2000"
show-word-limit
/>
</div>
<div class="param-line pt">
<span class="label">视频比例:</span>
</div>
<div class="param-line">
<el-select v-model="store.textToVideoParams.aspect_ratio" placeholder="选择比例">
<el-option
v-for="opt in videoAspectRatioOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</div>
</div>
<!-- 图生视频 -->
<div v-if="store.activeFunction === 'image_to_video'" class="function-panel">
<div class="param-line pt">
<span class="label">上传图片:</span>
</div>
<div class="param-line">
<ImageUpload
v-model="store.imageToVideoParams.image_input"
:max-count="2"
:multiple="true"
/>
</div>
<div class="param-line pt">
<span class="label">提示词:</span>
</div>
<div class="param-line">
<el-input
v-model="store.currentPrompt"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
placeholder="描述你想要的视频效果"
maxlength="2000"
show-word-limit
/>
</div>
<div class="param-line pt">
<span class="label">视频比例:</span>
</div>
<div class="param-line">
<el-select v-model="store.imageToVideoParams.aspect_ratio" placeholder="选择比例">
<el-option
v-for="opt in videoAspectRatioOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
<div class="function-params">
<div class="mb-3">
<div class="mb-2">
<label class="label text-left font-bold">模型选择</label>
</div>
<param-builder
v-model="store.formData"
v-model:required-keys="store.requiredKeys"
:items="store.functionParams[store.activeFunction]"
:progress="store.progress[store.activeFunction]"
/>
</div>
<!-- 提交按钮 -->
@@ -660,20 +386,13 @@
</template>
<script setup>
import '@/assets/css/jimeng.scss'
import loadingIcon from '@/assets/img/loading.gif'
import ImageUpload from '@/components/ImageUpload.vue'
import ParamBuilder from '@/components/ParamBuilder.vue'
import Generating from '@/components/ui/Generating.vue'
import {
imageEffectsTemplateOptions,
imageSizeOptions,
useJimengStore,
videoAspectRatioOptions,
} from '@/store/jimeng'
import { useJimengStore } from '@/store/jimeng'
import { useSharedStore } from '@/store/sharedata'
import { dateFormat } from '@/utils/libs'
import { Switch } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { Waterfall } from 'vue-waterfall-plugin-next'
@@ -682,17 +401,6 @@ import 'vue-waterfall-plugin-next/dist/style.css'
const sharedStore = useSharedStore()
const waterfallOptions = sharedStore.waterfallOptions
// 获取分类图标
const getCategoryIcon = (category) => {
const iconMap = {
image_generation: 'iconfont icon-image',
image_editing: 'iconfont icon-edit',
image_effects: 'iconfont icon-chuangzuo',
video_generation: 'iconfont icon-video',
}
return iconMap[category] || 'iconfont icon-image'
}
const store = useJimengStore()
// 新增:瀑布流渲染完成状态
@@ -730,13 +438,6 @@ watch(
}
)
function handleTemplateChange(value) {
templatePreview.value = imageEffectsTemplateOptions.find((opt) => opt.value === value)?.preview
store.imageEffectsParams.prompt = imageEffectsTemplateOptions.find(
(opt) => opt.value === value
)?.label
}
function onWaterfallAfterRender() {
waterfallRendered.value = true
if (!store.loading && !store.isOver) {
@@ -768,150 +469,5 @@ function copyErrorMsg(msg) {
</script>
<style lang="scss" scoped>
.task-list {
.task-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 20px;
padding: 10px 0;
}
// 新增:增强任务项悬停动画
.task-item {
transition: box-shadow 3s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.5s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
border: 1.5px solid transparent;
border-radius: 12px;
background: #fff;
position: relative;
z-index: 1;
}
.task-item:hover {
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 1.5px 8px rgba(0, 0, 0, 0.1);
border-color: #a259ff;
transform: scale(1.025) translateY(-2px);
z-index: 10;
}
}
@media (max-width: 1200px) {
.task-list .task-grid {
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
}
@media (max-width: 768px) {
.task-list .task-grid {
grid-template-columns: 1fr;
}
}
.preview-video-wrapper {
position: relative;
width: 100%;
height: 100%;
.video-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.25);
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.2s;
z-index: 2;
}
&:hover .video-mask {
opacity: 1;
}
.play-btn {
width: 64px;
height: 64px;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
cursor: pointer;
z-index: 3;
transition: background 0.2s;
&:hover {
background: rgba(255, 255, 255, 0.4);
}
img {
width: 36px;
height: 36px;
}
}
}
.err-msg-clip {
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: normal;
}
.jimeng-template-select {
.el-select-dropdown__item {
height: 60px;
line-height: 60px;
}
}
// 新增:提示词指南样式
.prompt-guide {
margin: 12px 0 16px;
.guide-title {
display: flex;
align-items: center;
font-weight: 600;
color: #666;
}
.guide-content {
max-height: 220px;
overflow: auto;
line-height: 1.6;
font-size: 12px;
color: #555;
padding-right: 4px;
}
.guide-section {
margin-bottom: 10px;
}
.guide-subtitle {
font-weight: 600;
margin-bottom: 6px;
color: #333;
}
ul {
list-style: disc;
padding-left: 18px;
margin: 4px 0;
}
.quote {
margin: 8px 0;
padding: 8px 10px;
border-left: 3px solid #a3a3a3;
background: #f8f8f8;
border-radius: 4px;
color: #444;
}
}
@use '@/assets/css/jimeng.scss' as *;
</style>

View File

@@ -56,134 +56,55 @@
<h3 class="heading-3 mb-3">算力配置</h3>
<el-form-item>
<template #label>
<div class="label-title">
文生图算力
<el-tooltip
effect="dark"
content="用户使用文生图功能时消耗的算力"
raw-content
placement="right"
<div class="text-gray-500 text-sm">
生成图片消耗的积分包括文生图图生图图片编辑图片特效<span
class="text-red-500"
>单位积分/</span
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input-number
v-model="jimengConfig.power.text_to_image"
v-model="jimengConfig.power.image"
:min="1"
placeholder="请输入文生图算力消耗"
placeholder="请输入图片生成算力消耗"
/>
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
图生图算力
<el-tooltip
effect="dark"
content="用户使用图生图功能时消耗的算力"
raw-content
placement="right"
<div class="text-gray-500 text-sm">
生成视频消耗的积分包括文生视频图生视频<span class="text-red-500"
>单位积分/</span
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input-number
v-model="jimengConfig.power.image_to_image"
v-model="jimengConfig.power.video"
:min="1"
placeholder="请输入图生图算力消耗"
placeholder="请输入视频生成算力消耗"
/>
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
图片编辑算力
<el-tooltip
effect="dark"
content="用户使用图片编辑功能时消耗的算力"
raw-content
placement="right"
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
<div class="text-gray-500 text-sm">
生成数字人视频消耗的积分<span class="text-red-500">单位积分/</span>
</div>
</template>
<el-input-number
v-model="jimengConfig.power.image_edit"
v-model="jimengConfig.power.virtual_human"
:min="1"
placeholder="请输入图片编辑算力消耗"
placeholder="请输入数字人视频生成算力消耗"
/>
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
图片特效算力
<el-tooltip
effect="dark"
content="用户使用图片特效功能时消耗的算力"
raw-content
placement="right"
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
<div class="text-gray-500 text-sm">
生成视频动作迁移消耗的积分<span class="text-red-500">单位积分/</span>
</div>
</template>
<el-input-number
v-model="jimengConfig.power.image_effects"
v-model="jimengConfig.power.action_transfer"
:min="1"
placeholder="请输入图片特效算力消耗"
/>
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
文生视频算力
<el-tooltip
effect="dark"
content="用户使用文生视频功能时消耗的算力"
raw-content
placement="right"
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input-number
v-model="jimengConfig.power.text_to_video"
:min="1"
placeholder="请输入文生视频算力消耗"
/>
</el-form-item>
<el-form-item>
<template #label>
<div class="label-title">
图生视频算力
<el-tooltip
effect="dark"
content="用户使用图生视频功能时消耗的算力"
raw-content
placement="right"
>
<el-icon>
<InfoFilled />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input-number
v-model="jimengConfig.power.image_to_video"
:min="1"
placeholder="请输入图生视频算力消耗"
placeholder="请输入视频动作迁移算力消耗"
/>
</el-form-item>
</div>
@@ -201,7 +122,6 @@
<script setup>
import Alert from '@/components/ui/Alert.vue'
import { httpGet, httpPost } from '@/utils/http'
import { InfoFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'

View File

@@ -41,7 +41,7 @@
<script setup>
import ParamBuilder from '@/components/ParamBuilder.vue'
import { JimengFunctions, JimengParams } from '@/store/data'
import { JimengFunctions, JimengParams } from '@/store/data/jimeng_data'
import { ref } from 'vue'
const functions = JimengFunctions