| | |
| | | <template> |
| | | <!-- 搜索 --> |
| | | <!-- 搜索区域 --> |
| | | <ContentWrap> |
| | | <el-form |
| | | class="-mb-15px" |
| | |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button @click="handleQuery"> |
| | | <el-button @click="handleQuery" type="primary"> |
| | | <Icon icon="ep:search" class="mr-5px" /> |
| | | {{t('table.search')}} |
| | | </el-button> |
| | |
| | | </el-form> |
| | | </ContentWrap> |
| | | |
| | | <!-- 列表 --> |
| | | <!-- 视频列表 --> |
| | | <ContentWrap> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column :label="t('myCourse.videoCode')" align="center" prop="id" /> |
| | | <el-table-column :label="t('myCourse.videoName')" align="center" prop="name" /> |
| | | <!-- <el-table-column :label="t('myCourse.duration')" align="center" prop="duration">--> |
| | | <!-- <template #default="scope">--> |
| | | <!-- {{ formatDuration(scope.row.duration) }}--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | <el-table-column label="排队个数" align="center" prop="pos" > |
| | | <el-table v-loading="loading" :data="list" style="width: 100%"> |
| | | <el-table-column :label="t('myCourse.videoCode')" align="center" prop="id" width="100" /> |
| | | <el-table-column :label="t('myCourse.videoName')" align="center" prop="name" min-width="150" /> |
| | | <el-table-column label="排队个数" align="center" prop="pos" width="100"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.pos==0">视频正在合成...</span> |
| | | <span v-if="scope.row.pos==0">视频正在合成...</span> |
| | | <span v-else>{{ scope.row.pos }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="进度" align="center" prop="progressVideo"> |
| | | <el-table-column label="进度" align="center" prop="progressVideo" width="100"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.status==2">100%</span> |
| | | <span v-else>{{ calculateProgress(scope.row.progressVideo) }}%</span> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column :label="t('myCourse.courseName')" align="center" prop="courseName"> |
| | | <el-table-column :label="t('myCourse.courseName')" align="center" prop="courseName" min-width="150"> |
| | | <template #default="scope"> |
| | | <el-link type="primary" @click="goDetail(scope.row.courseId)">{{ scope.row.courseName }}</el-link> |
| | | </template> |
| | |
| | | :label="t('table.createTime')" |
| | | align="center" |
| | | prop="createTime" |
| | | width="120" |
| | | width="160" |
| | | :formatter="dateFormatter" |
| | | /> |
| | | <el-table-column |
| | | :label="t('myCourse.finishTime')" |
| | | align="center" |
| | | prop="finishTime" |
| | | width="120" |
| | | width="160" |
| | | :formatter="dateFormatter" |
| | | /> |
| | | <el-table-column :label="t('myCourse.SynthesisTime')" align="center"> |
| | | <el-table-column :label="t('myCourse.SynthesisTime')" align="center" width="120"> |
| | | <template #default="scope"> |
| | | {{ calculateDuration(scope.row.createTime, scope.row.finishTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column :label="t('myCourse.errorReason')" align="center" prop="errorReason"> |
| | | <el-table-column :label="t('myCourse.errorReason')" align="center" prop="errorReason" width="150"> |
| | | <template #default="scope"> |
| | | <el-tooltip :content="scope.row.errorReason || '--'" placement="top"> |
| | | <span> |
| | | {{ scope.row.errorReason ? (scope.row.errorReason.length > 20 ? scope.row.errorReason.slice(0, 20) + '...' : scope.row.errorReason) : '--' }} |
| | | {{ scope.row.errorReason ? (scope.row.errorReason.length > 10 ? scope.row.errorReason.slice(0, 10) + '...' : scope.row.errorReason) : '--' }} |
| | | </span> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column :label="t('myCourse.status')" align="center" prop="status"> |
| | | <el-table-column :label="t('myCourse.status')" align="center" prop="status" width="120"> |
| | | <template #default="scope"> |
| | | <dict-tag v-if="scope.row.status==2 && scope.row.subtitlesAddStatus!=null" :type="DICT_TYPE.video_zi" :value="scope.row.subtitlesAddStatus" /> |
| | | <dict-tag v-else :type="DICT_TYPE.VIDEO_STATUS" :value="scope.row.status" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column :label="t('table.action')" align="center" min-width="110" fixed="right"> |
| | | <el-table-column :label="t('table.action')" align="center" width="230" fixed="right"> |
| | | <template #default="scope"> |
| | | <template v-if="scope.row.status == 2"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="openPreview(scope.row)" |
| | | > |
| | | {{t('myCourse.preview')}} |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="handleDownload(scope.row.previewUrl,scope.row.courseName)" |
| | | > |
| | | {{t('myCourse.downloadVideo')}} |
| | | </el-button> |
| | | |
| | | </template> |
| | | <template v-if=" scope.row.status == 3"> |
| | | <el-button |
| | | link |
| | | type="warning" |
| | | @click="reMegerMedia(scope.row.id)" |
| | | > |
| | | {{t('myCourse.resynthesize')}} |
| | | </el-button> |
| | | </template> |
| | | <template v-if="scope.row.status == 2"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="openSubtitleDialog(scope.row.id)" |
| | | > |
| | | 字幕 |
| | | </el-button> |
| | | </template> |
| | | <template v-if="scope.row.subtitlesAddStatus == 2"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="handleDownload(scope.row.videoUrl,scope.row.courseName)" |
| | | > |
| | | 下载字幕合成视频 |
| | | </el-button> |
| | | </template> |
| | | <template v-if="scope.row.status == 2 || scope.row.status==3"> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | @click="handleDelete(scope.row.id)" |
| | | > |
| | | {{ t('action.del') }} |
| | | </el-button> |
| | | </template> |
| | | <el-button-group> |
| | | <template v-if="scope.row.status == 2"> |
| | | <el-button |
| | | type="text" |
| | | @click="openPreview(scope.row)" |
| | | plain |
| | | > |
| | | {{t('myCourse.preview')}} |
| | | </el-button> |
| | | <el-button |
| | | type="text" |
| | | @click="handleHeaderFooter(scope.row)" |
| | | plain |
| | | > |
| | | 片头片尾 |
| | | </el-button> |
| | | <template v-if="scope.row.status == 2 || scope.row.status==3"> |
| | | <el-button |
| | | type="text" |
| | | @click="handleDelete(scope.row.id)" |
| | | plain |
| | | > |
| | | {{ t('action.del') }} |
| | | </el-button> |
| | | </template> |
| | | <template v-if="scope.row.status == 3"> |
| | | <el-button |
| | | type="text" |
| | | @click="reMegerMedia(scope.row.id)" |
| | | plain |
| | | > |
| | | {{t('myCourse.resynthesize')}} |
| | | </el-button> |
| | | </template> |
| | | <template v-if="scope.row.status == 2"> |
| | | <el-button |
| | | type="text" |
| | | @click="openSubtitleDialog(scope.row.id)" |
| | | plain |
| | | > |
| | | 字幕 |
| | | </el-button> |
| | | </template> |
| | | </template> |
| | | <el-dropdown> |
| | | <el-button type="text" plain> |
| | | 更多<el-icon class="el-icon--right"><arrow-down /></el-icon> |
| | | </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item |
| | | v-if="scope.row.subtitlesAddStatus == 2" |
| | | @click="handleDownload(scope.row.videoUrl, scope.row.courseName + '_字幕合成视频')" |
| | | > |
| | | <Icon class="mr-2" />下载字幕合成视频 |
| | | </el-dropdown-item> |
| | | <el-dropdown-item |
| | | @click="handleDownload(scope.row.previewUrl, scope.row.courseName + '_视频')" |
| | | > |
| | | <Icon class="mr-2" />下载视频 |
| | | </el-dropdown-item> |
| | | <el-dropdown-item |
| | | v-if="scope.row.compositeVideo!=null" |
| | | @click="handleDownload(scope.row.compositeVideo, scope.row.courseName + '_片头片尾视频')" |
| | | > |
| | | <Icon class="mr-2" />下载片头片尾视频 |
| | | </el-dropdown-item> |
| | | <el-dropdown-item |
| | | v-if="scope.row.titles!=null && scope.row.trailer!=null" |
| | | @click="mergeHeaderFooter(scope.row.id)" |
| | | > |
| | | <Icon class="mr-2" />合成片头片尾视频 |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </el-button-group> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 分页 --> |
| | | <Pagination |
| | | :total="total" |
| | |
| | | @change="handleFileUpload" |
| | | /> |
| | | </el-button> |
| | | <!-- 当查看字幕按钮转圈时,字幕视频合成也转圈 --> |
| | | <el-button |
| | | type="primary" |
| | | @click="downloadSubtitles" |
| | |
| | | > |
| | | 保存字幕 |
| | | </el-button> |
| | | |
| | | </div> |
| | | |
| | | </el-form-item> |
| | | <el-form-item label="预览视频" v-if="subtitleForm.subtitlesAddStatus==2"> |
| | | <div style="width: 100%;"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="subtitleDialogVisible = false">关 闭</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 片头片尾设置弹框 --> |
| | | <el-dialog |
| | | v-model="headerFooterDialogVisible" |
| | | title="片头片尾设置" |
| | | width="50%" |
| | | > |
| | | <el-form :model="headerFooterForm" label-width="120px"> |
| | | <el-form-item label="片头视频"> |
| | | <UploadFile v-model="headerFooterForm.titles" :fileType="['mp4']" :limit="1" @on-success="handleFileSuccess('audition', $event)"/> |
| | | </el-form-item> |
| | | <el-form-item label="片尾视频"> |
| | | <UploadFile v-model="headerFooterForm.trailer" :fileType="['mp4']" :limit="1" @on-success="handleFileSuccess1('audition', $event)"/> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="headerFooterDialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="applyHeaderFooter" :loading="applyingHeaderFooter">应用</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <el-dialog |
| | | v-model="dialogVisible" |
| | | title="视频合成中" |
| | | width="50%" |
| | | > |
| | | <el-form :model="formData1" label-width="120px"> |
| | | <el-form-item label="视频格式"> |
| | | <el-select v-model="formData1.isvideo"> |
| | | <el-option :disabled="formData1.videoUrl==null" label="字幕视频" :value="1" /> |
| | | <el-option label="原视频" :value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="hecheng" :loading="applyingHeaderFooter">合成</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { DICT_TYPE } from '@/utils/dict' |
| | | import { dateFormatter } from '@/utils/formatTime' |
| | |
| | | import { getAccessToken, getTenantId } from "@/utils/auth" |
| | | import axios from 'axios' |
| | | import { config } from '@/config/axios/config' |
| | | import {videoMeger} from "@/api/pptTemplate"; |
| | | import {createVideo, createVideoMeger, videoMeger} from "@/api/pptTemplate"; |
| | | import { ArrowDown } from '@element-plus/icons-vue' |
| | | |
| | | const router = useRouter() |
| | | const message = useMessage() |
| | | const { t } = useI18n() |
| | | const polling = ref(false) |
| | | let pollingTimer: number | null = null |
| | | |
| | | //合成片头片尾视频 |
| | | const dialogVisible = ref(false) |
| | | const formData1 = reactive({ |
| | | isvideo: 2, |
| | | id: null as number | null |
| | | }) |
| | | // 视频列表相关数据 |
| | | const loading = ref(true) |
| | | const total = ref(0) |
| | |
| | | videoId: null as number | null, |
| | | timeThreshold: '0.05', |
| | | language: 'zh', |
| | | content: '' |
| | | content: '', |
| | | subtitlesUrl: '', |
| | | videoUrl: '', |
| | | courseName: '', |
| | | subtitlesAddStatus: null |
| | | }) |
| | | const generating = ref(false) |
| | | const saving = ref(false) |
| | | |
| | | // 片头片尾弹框相关 |
| | | const headerFooterDialogVisible = ref(false) |
| | | const headerFooterForm = reactive({ |
| | | id: null as number | null, |
| | | titles: '', |
| | | trailer: '', |
| | | }) |
| | | |
| | | const applyingHeaderFooter = ref(false) |
| | | const handleFileSuccess = (fileType,response) => { |
| | | if (fileType === 'audition') { |
| | | headerFooterForm.titles = response.data |
| | | } |
| | | }; |
| | | const handleFileSuccess1 = (fileType,response) => { |
| | | if (fileType === 'audition') { |
| | | headerFooterForm.trailer = response.data |
| | | } |
| | | }; |
| | | // 获取视频列表 |
| | | const getList = async () => { |
| | | loading.value = true |
| | |
| | | } |
| | | |
| | | // 下载文件 |
| | | const handleDownload = (url, courseName) => { |
| | | const handleDownload = (url, filename) => { |
| | | if (!url) { |
| | | message.warning("未找到资源文件!") |
| | | return |
| | | } |
| | | // window.open(url, '_blank'); |
| | | |
| | | const link = document.createElement('a') |
| | | link.href = url |
| | | link.download = courseName |
| | | link.download = filename || 'download' |
| | | link.target = '_blank' |
| | | document.body.appendChild(link) |
| | | link.click() |
| | |
| | | }) |
| | | } |
| | | |
| | | // 格式化视频时长 |
| | | const formatDuration = (milliseconds: number) => { |
| | | const seconds = Math.floor(milliseconds / 1000) |
| | | const hrs = Math.floor(seconds / 3600) |
| | | const mins = Math.floor((seconds % 3600) / 60) |
| | | const secs = seconds % 60 |
| | | return `${hrs > 0 ? `${hrs}时` : ''}${mins > 0 ? `${mins}分` : ''}${secs}秒` |
| | | } |
| | | // 计算进度 |
| | | const calculateProgress = (progressStr: number) => { |
| | | const calculateProgress = (progressStr) => { |
| | | if (!progressStr || typeof progressStr !== 'string') return 0; |
| | | |
| | | const parts = progressStr.split('/'); |
| | |
| | | } |
| | | |
| | | // 计算合成耗时 |
| | | const calculateDuration = (createTime: string, finishTime: string) => { |
| | | const calculateDuration = (createTime, finishTime) => { |
| | | if (!createTime || !finishTime) return '未完成' |
| | | |
| | | const start = new Date(createTime).getTime() |
| | |
| | | // 打开字幕弹框 |
| | | const openSubtitleDialog = async (videoId: number) => { |
| | | try { |
| | | |
| | | subtitleDialogVisible.value = true |
| | | subtitleForm.videoId = videoId |
| | | const videoDetail = await pptTemplateApi.myCourseDetail(videoId) |
| | | // 立即获取视频详情检查字幕状态 |
| | | subtitleForm.subtitlesAddStatus=videoDetail.subtitlesAddStatus |
| | | console.log('视频详情:', videoDetail) |
| | | |
| | | subtitleForm.subtitlesAddStatus = videoDetail.subtitlesAddStatus |
| | | subtitleForm.courseName = videoDetail.courseName |
| | | |
| | | if (videoDetail.subtitlesAddStatus === 2) { |
| | | subtitleForm.videoUrl = videoDetail.videoUrl || '' |
| | | generating.value=false |
| | | polling.value=false |
| | | }else if (videoDetail.subtitlesAddStatus === 1) { |
| | | generating.value = false |
| | | polling.value = false |
| | | } else if (videoDetail.subtitlesAddStatus === 1) { |
| | | subtitleForm.videoUrl = '' |
| | | generating.value=true |
| | | polling.value=true |
| | | generating.value = true |
| | | polling.value = true |
| | | }else { |
| | | subtitleForm.videoUrl = videoDetail.videoUrl || '' |
| | | generating.value = false |
| | | polling.value = false |
| | | } |
| | | if (videoDetail.subtitlesStatus === 2) { // 2 表示字幕已生成 |
| | | |
| | | if (videoDetail.subtitlesStatus === 2) { |
| | | generating.value = false |
| | | polling.value = false |
| | | if (videoDetail.subtitlesUrl) { |
| | | subtitleForm.subtitlesUrl = videoDetail.subtitlesUrl |
| | | subtitleForm.courseName=videoDetail.courseName |
| | | generating.value=false |
| | | polling.value=false |
| | | try { |
| | | // 尝试从URL获取字幕内容 |
| | | const response = await fetch(videoDetail.subtitlesUrl) |
| | | if (response.ok) { |
| | | const srtContent = await response.text() |
| | | subtitleForm.content = srtContent |
| | | } else { |
| | | // 如果URL不可用,检查是否有直接的字幕内容 |
| | | subtitleForm.content = videoDetail.subtitlesContent || '' |
| | | } |
| | | } catch (error) { |
| | |
| | | subtitleForm.content = videoDetail.subtitlesContent || '' |
| | | } |
| | | } else if (videoDetail.subtitlesContent) { |
| | | // 直接使用字幕内容 |
| | | subtitleForm.content = videoDetail.subtitlesContent |
| | | } |
| | | } else if (videoDetail.subtitlesStatus === 3) { |
| | | // 字幕未生成或生成失败,清空内容 |
| | | generating.value = false |
| | | polling.value = false |
| | | subtitleForm.content = '' |
| | | }else if (videoDetail.subtitlesStatus === 1) { |
| | | generating.value=true |
| | | polling.value=true |
| | | } else if (videoDetail.subtitlesStatus === 1) { |
| | | generating.value = true |
| | | polling.value = true |
| | | subtitleForm.content = '' |
| | | }else{ |
| | | generating.value = false |
| | | polling.value = false |
| | | } |
| | | } catch (error) { |
| | | console.error('获取视频详情失败:', error) |
| | | message.error('获取视频详情失败,请重试') |
| | | subtitleDialogVisible.value = false |
| | | } |
| | | console.log('视频详情:', generating) |
| | | } |
| | | |
| | | // 重置字幕表单 |
| | | const resetSubtitleForm = () => { |
| | | subtitleFormRef.value?.resetFields() |
| | | subtitleForm.videoId = null |
| | | subtitleForm.content = '' |
| | | } |
| | | |
| | | // 触发文件上传 |
| | |
| | | const generateSubtitles = async () => { |
| | | try { |
| | | await subtitleFormRef.value.validateField(['timeThreshold', 'language']) |
| | | console.log(subtitleForm) |
| | | |
| | | if (!subtitleForm.videoId) { |
| | | message.warning('视频ID不能为空') |
| | | return |
| | |
| | | sentenceGap: parseFloat(subtitleForm.timeThreshold), |
| | | lang: subtitleForm.language |
| | | } |
| | | |
| | | await pptTemplateApi.generateSubtitles(params) |
| | | message.success(subtitleForm.courseName+' '+'字幕生成任务已开始') |
| | | |
| | | const maxAttempts = 20000 |
| | | const interval = 3000 |
| | | let attempts = 0 |
| | |
| | | |
| | | try { |
| | | const videoDetail = await pptTemplateApi.myCourseDetail(subtitleForm.videoId!) |
| | | console.log('轮询结果:', videoDetail) |
| | | |
| | | if (videoDetail.subtitlesStatus === 2) { |
| | | if (videoDetail.subtitlesUrl) { |
| | | try { |
| | |
| | | message.success(subtitleForm.courseName+' '+'字幕生成成功') |
| | | stopPolling() |
| | | } else if (videoDetail.subtitlesStatus === 3) { |
| | | // message.error(`字幕生成失败: ${videoDetail.errorReason || '未知原因'}`) |
| | | stopPolling() |
| | | } else if (attempts >= maxAttempts) { |
| | | message.warning(subtitleForm.courseName+' '+'字幕生成超时,请稍后手动检查') |
| | |
| | | poll() |
| | | } catch (error) { |
| | | console.error(subtitleForm.courseName+' '+'生成字幕出错:', error) |
| | | // message.error(`生成字幕失败: ${error.message || '未知错误'}`) |
| | | stopPolling() |
| | | } finally { |
| | | generating.value = false |
| | | } |
| | | } |
| | | |
| | | // 保存字幕 |
| | | const saveSubtitles = async () => { |
| | | try { |
| | | saving.value = true |
| | |
| | | const formData = new FormData() |
| | | formData.append('file', file) |
| | | |
| | | // 4. 上传文件 - 使用 axios 替代 request |
| | | // 4. 上传文件 |
| | | const uploadResponse = await axios({ |
| | | url: config.base_url+'/infra/file/upload', |
| | | method: 'post', |
| | |
| | | saving.value = false |
| | | } |
| | | } |
| | | |
| | | // 将文本内容格式化为SRT格式 |
| | | const formatToSrt = (content: string): string => { |
| | | if (content.trim().match(/^\d+\s+\d{2}:\d{2}:\d{2},\d{3}\s-->\s\d{2}:\d{2}:\d{2},\d{3}/)) { |
| | |
| | | return srtContent |
| | | } |
| | | |
| | | // 停止轮询 |
| | | const stopPolling = () => { |
| | | if (pollingTimer) { |
| | | clearTimeout(pollingTimer) |
| | | pollingTimer = null |
| | | } |
| | | polling.value = false |
| | | } |
| | | //字幕视频合成 |
| | | // 字幕视频合成 |
| | | const downloadSubtitles = async () => { |
| | | try { |
| | | // 判断字幕内容是否为空 |
| | | if (!subtitleForm.content.trim()) { |
| | | message.warning('请先生成或上传字幕内容') |
| | | return |
| | |
| | | |
| | | try { |
| | | const videoDetail = await pptTemplateApi.myCourseDetail(subtitleForm.videoId!) |
| | | console.log('轮询字幕视频合成结果:', videoDetail) |
| | | |
| | | if (videoDetail.subtitlesAddStatus === 2) { |
| | | message.success(subtitleForm.courseName+' '+'字幕视频合成成功') |
| | | if (videoDetail.previewUrl) { |
| | | subtitleForm.content = '' // 清空当前字幕内容 |
| | | subtitleForm.content = '' |
| | | stopPolling() |
| | | subtitleDialogVisible.value = false |
| | | getList() // 刷新列表 |
| | | getList() |
| | | } |
| | | } else if (videoDetail.subtitlesAddStatus === 3) { |
| | | message.error(subtitleForm.courseName+' '+`字幕视频合成失败: ${videoDetail.errorReason || '未知原因'}`) |
| | |
| | | generating.value = false |
| | | } |
| | | } |
| | | |
| | | // 停止轮询 |
| | | const stopPolling = () => { |
| | | if (pollingTimer) { |
| | | clearTimeout(pollingTimer) |
| | | pollingTimer = null |
| | | } |
| | | polling.value = false |
| | | } |
| | | |
| | | // 处理片头片尾按钮点击 |
| | | const handleHeaderFooter =async (row) => { |
| | | console.log(row) |
| | | headerFooterForm.id = row.id |
| | | let details= await pptTemplateApi.myCourseDetail(row.id) |
| | | console.log(details) |
| | | headerFooterForm.titles = details.titles || '' |
| | | headerFooterForm.trailer = details.trailer || '' |
| | | headerFooterDialogVisible.value = true |
| | | } |
| | | // 应用片头片尾设置 |
| | | const applyHeaderFooter = async () => { |
| | | try { |
| | | console.log('应用片头片尾设置:', headerFooterForm) |
| | | const title = await pptTemplateApi.createVideo(headerFooterForm) |
| | | console.log('创建视频标题:', title) |
| | | if (title) { |
| | | message.success('片头片尾设置成功') |
| | | headerFooterDialogVisible.value = false |
| | | getList() |
| | | } |
| | | } catch (error) { |
| | | console.error('片头片尾设置出错:', error) |
| | | message.error('片头片尾设置出错') |
| | | } finally { |
| | | applyingHeaderFooter.value = false |
| | | } |
| | | } |
| | | //合成片头片尾视频 |
| | | const mergeHeaderFooter = async (id: number) => { |
| | | try { |
| | | let details= await pptTemplateApi.myCourseDetail(id) |
| | | formData1.value=details |
| | | dialogVisible.value = true |
| | | console.log(formData1.value) |
| | | } |
| | | catch (error) { |
| | | console.error(error) |
| | | } |
| | | |
| | | } |
| | | //合成片头片尾 |
| | | const hecheng = async () => { |
| | | try { |
| | | console.log(formData1.value) |
| | | applyingHeaderFooter.value = true |
| | | let obj={} |
| | | if (formData1.isvideo=='2'){ |
| | | obj={ |
| | | id:formData1.value.id, |
| | | titles:formData1.value.titles, |
| | | trailer:formData1.value.trailer, |
| | | courseName:formData1.value.courseName, |
| | | videoUrl:null, |
| | | previewUrl:formData1.value.previewUrl |
| | | } |
| | | const res = await pptTemplateApi.createVideoMeger(obj) |
| | | if (res) { |
| | | message.success('视频合成成功') |
| | | applyingHeaderFooter.value = true |
| | | dialogVisible.value = false |
| | | getList() |
| | | } |
| | | }else if (formData1.isvideo=='1'){ |
| | | obj={ |
| | | id:formData1.value.id, |
| | | titles:formData1.value.titles, |
| | | trailer:formData1.value.trailer, |
| | | courseName:formData1.value.courseName, |
| | | videoUrl:formData1.value.courseName, |
| | | previewUrl:null |
| | | } |
| | | const res = await pptTemplateApi.createVideoMeger(obj) |
| | | if (res) { |
| | | message.success('视频合成成功') |
| | | applyingHeaderFooter.value = true |
| | | dialogVisible.value = false |
| | | getList() |
| | | } |
| | | } |
| | | // loading.value = true |
| | | // |
| | | } |
| | | catch (error) { |
| | | console.error(error) |
| | | } |
| | | } |
| | | |
| | | // 清理定时器 |
| | | onBeforeUnmount(() => { |
| | | stopPolling() |
| | |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .textarea-wrapper { |
| | | position: relative; |
| | |
| | | } |
| | | |
| | | .scroll-outside { |
| | | /* 隐藏默认滚动条 */ |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .scroll-outside .el-textarea__inner { |
| | | /* 显示自定义滚动条 */ |
| | | overflow-y: auto; |
| | | /* 确保滚动条不会挤压内容 */ |
| | | padding-right: 0; |
| | | /* 可选:增加右边距为滚动条留出空间 */ |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | /* 可选:自定义滚动条样式 */ |
| | | .scroll-outside .el-textarea__inner::-webkit-scrollbar { |
| | | width: 8px; |
| | | } |
| | |
| | | background: #c0c4cc; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .el-button-group { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .el-dropdown { |
| | | margin-left: 0; |
| | | } |
| | | </style> |