send-stream

This commit is contained in:
wing
2025-11-19 00:12:47 +08:00
parent 7f53203245
commit 33abc33b58
21 changed files with 1630 additions and 2247 deletions

View File

@@ -4,14 +4,14 @@
<template>
<div class="space-y-4">
<h2 class="text-xl font-bold">生成数字人</h2>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
<section class="bg-white p-4 rounded shadow lg:col-span-1">
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
<section class="p-4 bg-white rounded shadow lg:col-span-1">
<div class="space-y-3">
<div class="text-gray-600 text-sm">形象背景脚本分辨率字幕等配置</div>
<button class="px-4 py-2 bg-purple-600 text-white rounded">生成视频</button>
<div class="text-sm text-gray-600">形象背景脚本分辨率字幕等配置</div>
<button class="px-4 py-2 text-white bg-purple-600 rounded">生成视频</button>
</div>
</section>
<section class="bg-white p-4 rounded shadow lg:col-span-2">
<section class="p-4 bg-white rounded shadow lg:col-span-2">
<div class="text-gray-500">视频预览任务队列渲染进度</div>
</section>
</div>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,14 @@
</template>
上传素材
</a-button>
<a-button
type="primary"
ghost
:disabled="selectedFileIds.length === 0"
@click="handleOpenMixModal"
>
素材混剪
</a-button>
<a-button
v-if="selectedFileIds.length > 0"
type="primary"
@@ -142,11 +150,47 @@
@confirm="handleConfirmUpload"
@cancel="handleUploadCancel"
/>
<a-modal
v-model:open="mixModalVisible"
title="素材混剪"
centered
:confirm-loading="mixing"
ok-text="提交混剪"
cancel-text="取消"
@ok="handleMixConfirm"
@cancel="handleMixCancel"
>
<div class="mix-modal__summary">
<p>选中素材:{{ selectedFiles.length }} 个</p>
<p>视频素材:{{ selectedVideoUrls.length }} 个</p>
<p>背景音乐:{{ selectedAudioUrls.length }} 个</p>
</div>
<a-form layout="vertical">
<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"
/>
</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>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, computed, onMounted } from 'vue'
import { message, Modal } from 'ant-design-vue'
import {
UploadOutlined,
@@ -154,6 +198,7 @@ import {
FileOutlined
} from '@ant-design/icons-vue'
import { MaterialService } from '@/api/material'
import { MixService } from '@/api/mix'
import MaterialUploadModal from '@/components/material/MaterialUploadModal.vue'
import { formatFileSize, formatDate } from '@/utils/file'
@@ -163,6 +208,8 @@ const fileList = ref([])
const selectedFileIds = ref([])
const uploadModalVisible = ref(false)
const uploading = ref(false)
const mixModalVisible = ref(false)
const mixing = ref(false)
// 筛选条件
const filters = reactive({
@@ -370,6 +417,111 @@ const handleImageError = (e) => {
img.style.display = 'none'
}
const selectedFiles = computed(() =>
fileList.value.filter((file) => selectedFileIds.value.includes(file.id))
)
const isVideoFile = (file) => {
if (!file) return false
if (file.isVideo) return true
if (file.fileCategory === 'video') return true
if (typeof file.fileType === 'string' && file.fileType.startsWith('video')) return true
return false
}
const isAudioFile = (file) => {
if (!file) return false
if (file.fileCategory === 'audio') return true
if (file.fileType === 'audio') return true
if (typeof file.fileType === 'string' && file.fileType.startsWith('audio')) return true
return false
}
const selectedVideoUrls = computed(() =>
selectedFiles.value.map((file) => (isVideoFile(file) ? file?.fileUrl || file?.previewUrl : null)).filter(Boolean)
)
const selectedAudioUrls = computed(() =>
selectedFiles.value.map((file) => (isAudioFile(file) ? file?.fileUrl || file?.previewUrl : null)).filter(Boolean)
)
const mixForm = reactive({
title: '',
text: '',
produceCount: 1
})
const resetMixForm = () => {
mixForm.title = ''
mixForm.text = ''
mixForm.produceCount = 1
}
const handleOpenMixModal = () => {
if (selectedFileIds.value.length === 0) {
message.warning('请先选择至少一个素材')
return
}
if (selectedVideoUrls.value.length === 0) {
message.warning('请至少选择一个视频素材')
return
}
if (selectedAudioUrls.value.length === 0) {
message.warning('请至少选择一个背景音乐素材')
return
}
mixModalVisible.value = true
}
const handleMixCancel = () => {
mixModalVisible.value = false
}
const handleMixConfirm = async () => {
const title = mixForm.title.trim()
const text = mixForm.text.trim()
if (!title) {
message.warning('请输入视频标题')
return
}
if (!text) {
message.warning('请输入文案内容')
return
}
const produceCount = Math.max(1, Math.min(10, Number(mixForm.produceCount) || 1))
if (selectedVideoUrls.value.length === 0) {
message.warning('请至少选择一个视频素材')
return
}
if (selectedAudioUrls.value.length === 0) {
message.warning('请至少选择一个背景音乐素材')
return
}
mixing.value = true
try {
const { data } = await MixService.batchProduceAlignment({
title,
text,
videoUrls: selectedVideoUrls.value,
bgMusicUrls: selectedAudioUrls.value,
produceCount
})
const jobIds = Array.isArray(data) ? data : []
message.success(
jobIds.length > 0
? `混剪任务提交成功JobId${jobIds.join(', ')}`
: '混剪任务提交成功'
)
mixModalVisible.value = false
resetMixForm()
} catch (error) {
console.error('混剪失败:', error)
message.error(error?.message || '混剪任务提交失败,请重试')
} finally {
mixing.value = false
}
}
// 初始化
onMounted(() => {
loadFileList()
@@ -524,5 +676,20 @@ onMounted(() => {
color: var(--color-text-3);
}
.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>

View File

@@ -1,22 +0,0 @@
<script setup>
</script>
<template>
<div class="space-y-4">
<h2 class="text-xl font-bold">素材混剪</h2>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
<section class="bg-white p-4 rounded shadow lg:col-span-1">
<div class="text-gray-600 text-sm">文案拆解与镜头建议</div>
</section>
<section class="bg-white p-4 rounded shadow lg:col-span-2">
<div class="text-gray-500">素材匹配与时间线导出到剪映</div>
</section>
</div>
</div>
</template>
<style scoped>
</style>