文生视频和图生视频功能完成

This commit is contained in:
GeekMaster
2025-07-23 19:11:30 +08:00
parent 54fe49de5d
commit a3f6a641aa
20 changed files with 640 additions and 610 deletions

View File

@@ -1,61 +1,97 @@
<template>
<div class="image-upload">
<div class="upload-list" v-if="imageList.length > 0">
<div v-for="(image, index) in imageList" :key="index" class="upload-item">
<el-image
:src="image"
:preview-src-list="imageList"
:initial-index="index"
fit="cover"
class="upload-image"
/>
<div class="upload-overlay">
<el-button
type="danger"
:icon="Delete"
size="small"
circle
@click="removeImage(index)"
class="remove-btn"
/>
<!-- 单图模式 -->
<template v-if="props.maxCount === 1">
<div class="single-upload">
<div v-if="imageList.length === 0" class="upload-btn">
<el-upload
drag
:auto-upload="true"
:show-file-list="false"
:http-request="handleUpload"
:multiple="false"
accept="image/*"
class="uploader"
>
<div class="upload-placeholder">
<el-icon :size="20"><UploadFilled /></el-icon>
<span>上传图片</span>
</div>
</el-upload>
</div>
<div v-else class="upload-item single-image-item">
<el-image :src="imageList[0]" fit="cover" class="upload-image" />
<div class="upload-overlay" style="opacity: 1">
<el-button
type="danger"
:icon="Delete"
size="small"
circle
@click="removeImage(0)"
class="remove-btn"
/>
</div>
</div>
</div>
</template>
<!-- 上传按钮 -->
<div v-if="!multiple || imageList.length < maxCount" class="upload-btn">
<!-- 多图模式 -->
<template v-else>
<div class="upload-list" v-if="imageList.length > 0">
<div v-for="(image, index) in imageList" :key="index" class="upload-item">
<el-image :src="image" fit="cover" class="upload-image" />
<div class="upload-overlay">
<el-button
type="danger"
:icon="Delete"
size="small"
circle
@click="removeImage(index)"
class="remove-btn"
/>
</div>
</div>
<!-- 上传按钮 -->
<div v-if="!multiple || imageList.length < maxCount" class="upload-btn">
<el-upload
drag
:auto-upload="true"
:show-file-list="false"
:http-request="handleUpload"
:multiple="multiple"
accept="image/*"
class="uploader"
:limit="maxCount"
>
<div class="upload-placeholder">
<el-icon :size="20"><UploadFilled /></el-icon>
<span>上传图片</span>
</div>
</el-upload>
</div>
</div>
<!-- 初始上传区域 -->
<div v-else class="upload-area">
<el-upload
drag
:auto-upload="true"
:show-file-list="false"
:http-request="handleUpload"
:multiple="multiple"
accept="image/*"
class="uploader"
:limit="maxCount"
>
<div class="upload-placeholder">
<el-icon :size="20"><Plus /></el-icon>
<span>上传图片</span>
</div>
<el-icon :size="40" class="el-icon--upload"><UploadFilled /></el-icon>
<div class="el-upload__text">拖拽图片到此处 <em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip text-center">
支持 JPGPNG 格式最多上传 {{ maxCount }} 单张最大 5MB
</div>
</template>
</el-upload>
</div>
</div>
<!-- 初始上传区域 -->
<div v-else class="upload-area">
<el-upload
:auto-upload="true"
:show-file-list="false"
:http-request="handleUpload"
accept="image/*"
class="uploader"
>
<div class="upload-placeholder">
<el-icon :size="40"><Plus /></el-icon>
<div class="upload-text">
<p>点击上传图片</p>
<p class="upload-tip">支持 JPGPNG 格式最大 10MB</p>
</div>
</div>
</el-upload>
</div>
</template>
<!-- 上传进度 -->
<el-progress
@@ -69,7 +105,8 @@
<script setup>
import { httpPost } from '@/utils/http'
import { Delete, Plus } from '@element-plus/icons-vue'
import { replaceImg } from '@/utils/libs'
import { Delete, UploadFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { computed, ref } from 'vue'
@@ -97,14 +134,14 @@ const uploadProgress = ref(0)
// 图片列表
const imageList = computed({
get() {
if (props.multiple) {
if (props.multiple || props.maxCount > 1) {
return Array.isArray(props.modelValue) ? props.modelValue : []
} else {
return props.modelValue ? [props.modelValue] : []
}
},
set(value) {
if (props.multiple) {
if (props.multiple || props.maxCount > 1) {
emit('update:modelValue', value)
} else {
emit('update:modelValue', value[0] || '')
@@ -112,6 +149,7 @@ const imageList = computed({
},
})
const uploadCount = ref(1)
// 处理上传
const handleUpload = async (uploadFile) => {
const file = uploadFile.file
@@ -122,17 +160,18 @@ const handleUpload = async (uploadFile) => {
return
}
// 检查文件大小 (10MB)
if (file.size > 10 * 1024 * 1024) {
ElMessage.error('图片大小不能超过 10MB')
// 检查文件大小 (5MB)
if (file.size > 5 * 1024 * 1024) {
ElMessage.error('图片大小不能超过 5MB')
return
}
// 检查数量限制
if (props.multiple && imageList.value.length >= props.maxCount) {
if (uploadCount.value > props.maxCount) {
ElMessage.error(`最多只能上传 ${props.maxCount} 张图片`)
return
}
uploadCount.value++
uploading.value = true
uploadProgress.value = 0
@@ -153,10 +192,10 @@ const handleUpload = async (uploadFile) => {
clearInterval(progressTimer)
uploadProgress.value = 100
const imageUrl = response.data.url
const imageUrl = replaceImg(response.data.url)
// 更新图片列表
if (props.multiple) {
if (props.multiple || props.maxCount > 1) {
const newList = [...imageList.value, imageUrl]
imageList.value = newList
} else {
@@ -178,114 +217,114 @@ const removeImage = (index) => {
const newList = [...imageList.value]
newList.splice(index, 1)
imageList.value = newList
uploadCount.value--
}
</script>
<style lang="stylus" scoped>
.image-upload
width 100%
<style lang="stylus">
.image-upload {
width: 100%;
}
.upload-list
display flex
flex-wrap wrap
gap 10px
.single-upload {
width: 100px;
height: 100px;
position: relative;
}
.upload-item
position relative
width 100px
height 100px
border-radius 6px
overflow hidden
border 1px solid #dcdfe6
.single-image-item {
width: 100px;
height: 100px;
position: relative;
border-radius: 6px;
overflow: hidden;
border: 1px solid #dcdfe6;
}
.upload-image
width 100%
height 100%
.upload-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.upload-overlay
position absolute
top 0
left 0
right 0
bottom 0
background rgba(0, 0, 0, 0.5)
display flex
align-items center
justify-content center
opacity 0
transition opacity 0.3s
.upload-item {
position: relative;
width: 100px;
height: 100px;
border-radius: 6px;
overflow: hidden;
border: 1px solid #dcdfe6;
.remove-btn
background rgba(245, 108, 108, 0.8)
border none
color white
.upload-image {
width: 100%;
height: 100%;
}
&:hover .upload-overlay
opacity 1
.upload-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s;
.upload-btn
width 100px
height 100px
border 2px dashed #dcdfe6
border-radius 6px
display flex
align-items center
justify-content center
cursor pointer
transition all 0.3s
.remove-btn {
background: rgba(245, 108, 108, 0.8);
border: none;
color: white;
}
}
&:hover
border-color #409eff
color #409eff
&:hover .upload-overlay {
opacity: 1;
}
}
.uploader
width 100%
height 100%
.upload-btn {
.uploader {
width: 100%;
.upload-placeholder
display flex
flex-direction column
align-items center
gap 5px
font-size 12px
color #8c939d
.el-upload-dragger {
width: 100px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
font-size: 12px;
color: #8c939d;
}
}
.upload-area
border 2px dashed #dcdfe6
border-radius 6px
padding 40px
text-align center
cursor pointer
transition all 0.3s
.upload-area {
.el-upload-dragger {
width: 100%;
}
.uploader {
width: 100%;
}
}
&:hover
border-color #409eff
.upload-progress {
margin-top: 10px;
}
.uploader
width 100%
.upload-placeholder
display flex
flex-direction column
align-items center
gap 10px
color #8c939d
.upload-text
p
margin 5px 0
.upload-tip
font-size 12px
color #c0c4cc
.upload-progress
margin-top 10px
:deep(.el-upload)
width 100%
height 100%
display flex
align-items center
justify-content center
:deep(.el-upload) {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>