feat: 视频问题
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="modalVisible"
|
||||
title="批量分组"
|
||||
centered
|
||||
@ok="handleConfirm"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="选择分组" required>
|
||||
<a-select
|
||||
v-model:value="selectedGroupId"
|
||||
placeholder="请选择要添加到的分组"
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-select-option v-for="group in groupList" :key="group.id" :value="group.id">
|
||||
{{ group.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<div style="margin-top: 16px; padding: 12px; background: var(--color-bg-2); border-radius: var(--radius-card);">
|
||||
<p style="margin: 0; font-size: 13px; color: var(--color-text-2);">
|
||||
{{ groupingInfo }}
|
||||
</p>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
const props = defineProps({
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
groupList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 可选的信息,组件会显示但不会强依赖
|
||||
fileName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fileCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:open', 'confirm', 'cancel'])
|
||||
|
||||
// 数据
|
||||
const selectedGroupId = ref(null)
|
||||
const modalVisible = ref(false)
|
||||
|
||||
// 计算分组提示信息
|
||||
const groupingInfo = computed(() => {
|
||||
if (props.fileName) {
|
||||
return `将为文件 "${props.fileName}" 添加到选中的分组中`
|
||||
}
|
||||
if (props.fileCount > 0) {
|
||||
return `将为 ${props.fileCount} 个文件添加到选中的分组中`
|
||||
}
|
||||
return '将为选中文件添加到选中的分组中'
|
||||
})
|
||||
|
||||
// 监听 open 变化
|
||||
watch(() => props.open, (newVal) => {
|
||||
modalVisible.value = newVal
|
||||
if (!newVal) {
|
||||
selectedGroupId.value = null
|
||||
}
|
||||
})
|
||||
|
||||
// 处理确认
|
||||
const handleConfirm = () => {
|
||||
if (!selectedGroupId.value) {
|
||||
message.warning('请选择分组')
|
||||
return
|
||||
}
|
||||
|
||||
emit('confirm', selectedGroupId.value)
|
||||
handleCancel()
|
||||
}
|
||||
|
||||
// 处理取消
|
||||
const handleCancel = () => {
|
||||
modalVisible.value = false
|
||||
selectedGroupId.value = null
|
||||
emit('update:open', false)
|
||||
emit('cancel')
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,258 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="modalVisible"
|
||||
title="素材混剪"
|
||||
centered
|
||||
:confirm-loading="loading"
|
||||
ok-text="提交混剪"
|
||||
cancel-text="取消"
|
||||
@ok="handleConfirm"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<div class="mix-modal__summary">
|
||||
<p>视频分组:{{ getGroupName(videoGroupId) || '未选择' }}</p>
|
||||
<p>视频数量:{{ videoGroupFiles.length }} 个</p>
|
||||
<p>背景音乐:{{ selectedBgMusic?.fileName || '未选择' }}</p>
|
||||
<p style="margin-top: 8px; font-size: 12px; color: var(--color-text-3);">
|
||||
系统将根据文案自动生成配音并匹配视频片段
|
||||
</p>
|
||||
</div>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="选择视频分组" required>
|
||||
<a-select
|
||||
v-model:value="videoGroupId"
|
||||
placeholder="请选择视频分组"
|
||||
style="width: 100%"
|
||||
@change="handleVideoGroupChange"
|
||||
>
|
||||
<a-select-option v-for="group in groupList" :key="group.id" :value="group.id">
|
||||
{{ group.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="选择背景音乐" required>
|
||||
<a-select
|
||||
v-model:value="selectedBgMusic"
|
||||
placeholder="请选择背景音乐"
|
||||
style="width: 100%"
|
||||
show-search
|
||||
:filter-option="(input, option) => option.children.toLowerCase().includes(input.toLowerCase())"
|
||||
>
|
||||
<a-select-option v-for="audio in allAudioFiles" :key="audio.id" :value="audio.id">
|
||||
{{ audio.fileName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="视频标题" required>
|
||||
<a-input v-model:value="mixForm.title" placeholder="请输入生成视频标题" />
|
||||
</a-form-item>
|
||||
<a-form-item label="文案内容" required>
|
||||
<a-textarea
|
||||
v-model:value="mixForm.text"
|
||||
placeholder="请输入文案(每句话用句号分隔)"
|
||||
:rows="4"
|
||||
/>
|
||||
<div style="margin-top: 8px; font-size: 12px; color: var(--color-text-3);">
|
||||
文案将用于生成 TTS 配音,每句话对应一个视频片段
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="生成成片数量" required>
|
||||
<a-input-number
|
||||
v-model:value="mixForm.produceCount"
|
||||
:min="1"
|
||||
:max="10"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { MaterialService } from '@/api/material'
|
||||
|
||||
const props = defineProps({
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
groupList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
allAudioFiles: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:open', 'confirm', 'cancel'])
|
||||
|
||||
// 数据
|
||||
const modalVisible = ref(false)
|
||||
const videoGroupId = ref(null)
|
||||
const selectedBgMusic = ref(null)
|
||||
const videoGroupFiles = ref([])
|
||||
|
||||
const mixForm = reactive({
|
||||
title: '',
|
||||
text: '',
|
||||
produceCount: 1
|
||||
})
|
||||
|
||||
// 获取分组名称
|
||||
const getGroupName = (groupId) => {
|
||||
if (!groupId) return ''
|
||||
const group = props.groupList.find(g => g.id === groupId)
|
||||
return group?.name || ''
|
||||
}
|
||||
|
||||
// 监听 open 变化
|
||||
watch(() => props.open, (newVal) => {
|
||||
modalVisible.value = newVal
|
||||
if (newVal) {
|
||||
resetForm()
|
||||
// 组件打开时,可以在这里加载音频文件,但最好由父组件传入
|
||||
}
|
||||
})
|
||||
|
||||
// 处理视频分组变化
|
||||
const handleVideoGroupChange = async (groupId) => {
|
||||
console.log('[MaterialMixModal] handleVideoGroupChange called with groupId:', groupId)
|
||||
|
||||
if (!groupId) {
|
||||
videoGroupFiles.value = []
|
||||
console.log('[MaterialMixModal] groupId is empty, videoGroupFiles cleared')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[MaterialMixModal] Loading video files for group:', groupId)
|
||||
|
||||
try {
|
||||
const res = await MaterialService.getFilePage({
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
groupId: groupId,
|
||||
fileCategory: 'video'
|
||||
})
|
||||
if (res.code === 0) {
|
||||
videoGroupFiles.value = res.data.list || []
|
||||
console.log('[MaterialMixModal] Loaded video files:', videoGroupFiles.value.length, 'files')
|
||||
} else {
|
||||
console.error('[MaterialMixModal] Failed to load video files:', res.msg)
|
||||
message.error(res.msg || '加载分组文件失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[MaterialMixModal] Error loading video files:', error)
|
||||
message.error('加载分组文件失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
mixForm.title = ''
|
||||
mixForm.text = ''
|
||||
mixForm.produceCount = 1
|
||||
videoGroupId.value = null
|
||||
selectedBgMusic.value = null
|
||||
videoGroupFiles.value = []
|
||||
}
|
||||
|
||||
// 暴露给父组件的方法
|
||||
defineExpose({
|
||||
resetForm
|
||||
})
|
||||
|
||||
// 处理确认
|
||||
const handleConfirm = async () => {
|
||||
const title = mixForm.title.trim()
|
||||
const text = mixForm.text.trim()
|
||||
|
||||
if (!videoGroupId.value) {
|
||||
message.warning('请选择视频分组')
|
||||
return
|
||||
}
|
||||
if (!selectedBgMusic.value) {
|
||||
message.warning('请选择背景音乐')
|
||||
return
|
||||
}
|
||||
if (!title) {
|
||||
message.warning('请输入视频标题')
|
||||
return
|
||||
}
|
||||
if (!text) {
|
||||
message.warning('请输入文案内容')
|
||||
return
|
||||
}
|
||||
|
||||
// 如果当前没有视频文件,重新加载一次
|
||||
if (videoGroupFiles.value.length === 0) {
|
||||
message.loading('正在加载视频文件...', 0)
|
||||
await handleVideoGroupChange(videoGroupId.value)
|
||||
message.destroy()
|
||||
}
|
||||
|
||||
if (videoGroupFiles.value.length === 0) {
|
||||
message.warning('所选分组下没有视频文件,请检查分组设置或更换分组')
|
||||
return
|
||||
}
|
||||
|
||||
// 提取视频URL和音频URL
|
||||
const videoUrls = videoGroupFiles.value
|
||||
.map(file => file?.fileUrl || file?.previewUrl)
|
||||
.filter(Boolean)
|
||||
|
||||
const bgMusicUrls = [selectedBgMusic.value?.fileUrl || selectedBgMusic.value?.previewUrl].filter(Boolean)
|
||||
|
||||
if (videoUrls.length === 0) {
|
||||
message.warning('视频分组中没有有效的视频文件')
|
||||
return
|
||||
}
|
||||
if (bgMusicUrls.length === 0) {
|
||||
message.warning('所选背景音乐无效')
|
||||
return
|
||||
}
|
||||
|
||||
const produceCount = Math.max(1, Math.min(10, Number(mixForm.produceCount) || 1))
|
||||
|
||||
emit('confirm', {
|
||||
title,
|
||||
text,
|
||||
videoUrls,
|
||||
bgMusicUrls,
|
||||
produceCount
|
||||
})
|
||||
}
|
||||
|
||||
// 处理取消
|
||||
const handleCancel = () => {
|
||||
modalVisible.value = false
|
||||
emit('update:open', false)
|
||||
emit('cancel')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mix-modal__summary {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px;
|
||||
background: var(--color-bg-2);
|
||||
border: 1px dashed var(--color-border);
|
||||
border-radius: var(--radius-card);
|
||||
font-size: 13px;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
|
||||
.mix-modal__summary p {
|
||||
margin: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
@@ -89,6 +89,10 @@ const props = defineProps({
|
||||
uploading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fileCategory: {
|
||||
type: String,
|
||||
default: 'video'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -208,7 +212,9 @@ const handleConfirm = () => {
|
||||
return
|
||||
}
|
||||
|
||||
emit('confirm', filesWithCover, DEFAULT_FILE_CATEGORY)
|
||||
// 使用传入的fileCategory,如果没有则使用默认值
|
||||
const category = props.fileCategory || DEFAULT_FILE_CATEGORY
|
||||
emit('confirm', filesWithCover, category)
|
||||
}
|
||||
|
||||
// 处理 visible 变化
|
||||
|
||||
Reference in New Issue
Block a user