From 323bd81573def2a059c7a2caeb0ba532279c4893 Mon Sep 17 00:00:00 2001 From: 康鲁杰 <60095866+KangLujie@users.noreply.github.com> Date: 星期四, 17 四月 2025 11:37:27 +0800 Subject: [PATCH] 我的视频 --- easegen-front/src/views/myCourse/index.vue | 812 ++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 540 insertions(+), 272 deletions(-) diff --git a/easegen-front/src/views/myCourse/index.vue b/easegen-front/src/views/myCourse/index.vue index 07b30af..2600a2b 100644 --- a/easegen-front/src/views/myCourse/index.vue +++ b/easegen-front/src/views/myCourse/index.vue @@ -33,23 +33,37 @@ <!-- 瑙嗛鍒楄〃 --> <ContentWrap> <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="t('myCourse.videoName')" align="center" prop="name" min-width="180" /> + <el-table-column :label="t('myCourse.courseName')" align="center" prop="courseName" min-width="180"> + <template #default="scope"> + <el-link type="primary" @click="goDetail(scope.row.courseId)">{{ scope.row.courseName }}</el-link> + </template> + </el-table-column> + <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="杩涘害" align="center" prop="progressVideo" width="100"> + <template #default="scope"> + <span v-if="scope.row.status==2">100%</span> + <span v-else>{{ Math.max(1, Math.min(calculateProgress(scope.row.progressVideo), 99)) }}%</span> + </template> + </el-table-column> <el-table-column label="鎺掗槦涓暟" align="center" prop="pos" width="100"> <template #default="scope"> <span v-if="scope.row.pos==0">瑙嗛姝e湪鍚堟垚...</span> <span v-else>{{ scope.row.pos }}</span> </template> </el-table-column> - <el-table-column label="杩涘害" align="center" prop="progressVideo" width="100"> + <el-table-column :label="t('myCourse.errorReason')" align="center" prop="errorReason" width="150"> <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" min-width="150"> - <template #default="scope"> - <el-link type="primary" @click="goDetail(scope.row.courseId)">{{ scope.row.courseName }}</el-link> + <el-tooltip :content="scope.row.errorReason || '--'" placement="top"> + <span> + {{ 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 @@ -71,100 +85,49 @@ {{ calculateDuration(scope.row.createTime, scope.row.finishTime) }} </template> </el-table-column> - <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 > 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" 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" width="230" fixed="right"> + <el-table-column :label="t('table.action')" align="center" width="280" fixed="right"> <template #default="scope"> <el-button-group> <template v-if="scope.row.status == 2"> <el-button - type="text" + type="primary" + link @click="openPreview(scope.row)" - plain > {{t('myCourse.preview')}} </el-button> <el-button - type="text" + type="primary" + link + @click="handleDownload(scope.row.previewUrl, scope.row.courseName + '_瑙嗛')" + v-if="scope.row.previewUrl!=null" + > + 涓嬭浇 + </el-button> + <el-button + type="primary" + link + @click="openSubtitleDialog(scope.row.id)" + v-if="scope.row.status == 2" + > + 瀛楀箷 + </el-button> + <el-button + type="primary" + link @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 + type="danger" + link + @click="handleDelete(scope.row.id)" + v-if="scope.row.status == 2 || scope.row.status==3 || scope.row.status==4" + > + {{ t('action.del') }} </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 - v-if="scope.row.previewUrl!=null" - @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> + </template> </el-button-group> </template> </el-table-column> @@ -186,140 +149,258 @@ <el-dialog v-model="subtitleDialogVisible" title="瀛楀箷鏌ョ湅淇敼" - width="60%" + width="70%" + class="subtitle-dialog" > - <el-form :model="subtitleForm" ref="subtitleFormRef"> - <el-row :gutter="20"> - <el-col :span="7"> - <el-form-item label="鏂彞鏃堕棿闃堝��" prop="timeThreshold" :rules="[ - { required: true, message: '璇疯緭鍏ユ柇鍙ユ椂闂撮槇鍊�', trigger: 'blur' }, - { pattern: /^\d+(\.\d+)?$/, message: '璇疯緭鍏ユ湁鏁堟暟瀛�', trigger: 'blur' } + <el-tabs v-model="activeSubtitleTab"> + <el-tab-pane label="瀛楀箷璁剧疆" name="setting"> + <el-form :model="subtitleForm" ref="subtitleFormRef"> + <el-row :gutter="20"> + <el-col :span="7"> + <el-form-item label="鏂彞鏃堕棿闃堝��" prop="timeThreshold" :rules="[ + { required: true, message: '璇疯緭鍏ユ柇鍙ユ椂闂撮槇鍊�', trigger: 'blur' }, + { pattern: /^\d+(\.\d+)?$/, message: '璇疯緭鍏ユ湁鏁堟暟瀛�', trigger: 'blur' } + ]"> + <el-input v-model="subtitleForm.timeThreshold" placeholder="渚嬪锛�0.05" clearable /> + </el-form-item> + </el-col> + <el-col :span="7"> + <el-form-item label="璇█" prop="language" :rules="[ + { required: true, message: '璇烽�夋嫨璇█', trigger: 'change' } + ]"> + <el-select v-model="subtitleForm.language" placeholder="璇烽�夋嫨璇█" clearable> + <el-option label="涓枃" value="zh" /> + <el-option label="鑻辨枃" value="en" /> + </el-select> + </el-form-item> + </el-col> + <el-col :span="10"> + <el-form-item> + <el-button + type="primary" + @click="generateSubtitles" + :loading="subtitleForm.subtitlesStatus === 1" + :disabled="subtitleForm.subtitlesStatus === 1 || subtitleForm.subtitlesAddStatus === 1" + > + {{ subtitleForm.subtitlesStatus === 1 ? '瀛楀箷鐢熸垚涓�' : '鐢熸垚瀛楀箷' }} + </el-button> + <el-button + type="primary" + @click="triggerFileUpload" + :disabled="subtitleForm.subtitlesStatus === 1 || subtitleForm.subtitlesAddStatus === 1" + > + 涓婁紶SRT鏂囦欢 + <input + ref="fileInput" + type="file" + accept=".srt" + style="display: none" + @change="handleFileUpload" + /> + </el-button> + </el-form-item> + </el-col> + </el-row> + <el-form-item label="瀛楀箷鍐呭" prop="content" :rules="[ + { required: true, message: '璇峰厛鐢熸垚鎴栦笂浼犲瓧骞曞唴瀹�', trigger: 'blur' } ]"> - <el-input v-model="subtitleForm.timeThreshold" placeholder="渚嬪锛�0.05" clearable /> - </el-form-item> - </el-col> - <el-col :span="7"> - <el-form-item label="璇█" prop="language" :rules="[ - { required: true, message: '璇烽�夋嫨璇█', trigger: 'change' } - ]"> - <el-select v-model="subtitleForm.language" placeholder="璇烽�夋嫨璇█" clearable> - <el-option label="涓枃" value="zh" /> - <el-option label="鑻辨枃" value="en" /> - </el-select> - </el-form-item> - </el-col> - <el-col :span="10"> - <el-form-item> - <el-button - type="primary" - @click="generateSubtitles" - :loading="generating || polling" - > - 鐢熸垚瀛楀箷 - </el-button> - <el-button - type="primary" - @click="triggerFileUpload" - > - 涓婁紶SRT鏂囦欢 - <input - ref="fileInput" - type="file" - accept=".srt" - style="display: none" - @change="handleFileUpload" + <div style="width: 100%;" class="textarea-wrapper"> + <el-input + class="scroll-outside" + v-model="subtitleForm.content" + type="textarea" + :rows="20" + placeholder="瀛楀箷鍐呭灏嗘樉绀哄湪杩欓噷锛圫RT鏍煎紡锛�" + resize="none" + :disabled="!subtitleForm.content" + @input="handleSubtitleChange" /> - </el-button> - <el-button - type="primary" - @click="downloadSubtitles" - :loading="generating || polling" - > - 瀛楀箷瑙嗛鍚堟垚 - </el-button> + <div class="button-group"> + <el-button + type="primary" + @click="saveSubtitles" + :loading="saving" + :disabled="!subtitleForm.content || !isSubtitleModified" + > + 淇濆瓨瀛楀箷 + </el-button> + <el-button + type="primary" + @click="downloadSubtitles" + :loading="subtitleForm.subtitlesAddStatus === 1" + :disabled="!subtitleForm.content || subtitleForm.subtitlesStatus === 1" + > + {{ subtitleForm.subtitlesAddStatus === 1 ? '瀛楀箷瑙嗛鍚堟垚涓�' : '瀛楀箷瑙嗛鍚堟垚' }} + </el-button> + </div> + </div> </el-form-item> - </el-col> - </el-row> - <el-form-item label="瀛楀箷鍐呭" prop="content" :rules="[ - { required: true, message: '璇峰厛鐢熸垚鎴栦笂浼犲瓧骞曞唴瀹�', trigger: 'blur' } - ]"> - <div style="width: 100%;" class="textarea-wrapper"> - <el-input - class="scroll-outside" - v-model="subtitleForm.content" - type="textarea" - :rows="20" - placeholder="瀛楀箷鍐呭灏嗘樉绀哄湪杩欓噷锛圫RT鏍煎紡锛�" - resize="none" - /> - <el-button - style="margin-top: 20px;float: right;margin-left: 20px" - type="primary" - :disabled="!subtitleForm.subtitlesUrl" - @click="handleDownload(subtitleForm.subtitlesUrl,subtitleForm.courseName)" - > - {{t('myCourse.downloadSubtitles')}} - </el-button> - <el-button - style="margin-top: 20px;float: right" - type="primary" - @click="saveSubtitles" - :loading="saving" - :disabled="!subtitleForm.content" - > - 淇濆瓨瀛楀箷 - </el-button> - </div> - </el-form-item> - <el-form-item label="棰勮瑙嗛" v-if="subtitleForm.subtitlesAddStatus==2"> - <div style="width: 100%;"> - <video width="100%" :src="subtitleForm.videoUrl" controls></video> - <el-button - style="margin-top: 20px;float: right" - type="primary" - @click="handleDownload(subtitleForm.videoUrl,subtitleForm.videoUrl)" - > - 涓嬭浇瑙嗛 - </el-button> - </div> - </el-form-item> - </el-form> - - <template #footer> - <div class="dialog-footer"> - <el-button @click="subtitleDialogVisible = false">鍏� 闂�</el-button> - </div> - </template> + </el-form> + </el-tab-pane> + <el-tab-pane label="棰勮涓庝笅杞�" name="preview"> + <el-row :gutter="20"> + <el-col :span="24"> + <div class="preview-section"> + <h4>瀛楀箷瑙嗛</h4> + <div class="video-container"> + <video + v-if="subtitleForm.videoUrl" + :src="subtitleForm.videoUrl" + controls + class="preview-video" + ></video> + <div v-else class="no-video">鏆傛棤瀛楀箷瑙嗛</div> + </div> + <div class="button-group"> + <el-button + type="primary" + @click="handleDownload(subtitleForm.videoUrl, subtitleForm.courseName + '_瀛楀箷瑙嗛')" + :disabled="!subtitleForm.videoUrl" + > + 涓嬭浇瀛楀箷瑙嗛 + </el-button> + </div> + </div> + </el-col> + </el-row> + </el-tab-pane> + </el-tabs> </el-dialog> <!-- 鐗囧ご鐗囧熬璁剧疆寮规 --> <el-dialog v-model="headerFooterDialogVisible" title="鐗囧ご鐗囧熬璁剧疆" - width="50%" + width="70%" > - <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-tabs v-model="activeTab"> + <el-tab-pane label="璁剧疆鐗囧ご鐗囧熬" name="setting"> + <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-item> + <el-button type="primary" @click="applyHeaderFooter" :loading="applyingHeaderFooter">淇濆瓨璁剧疆</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + <el-tab-pane label="鍚堟垚瑙嗛" name="merge"> + <el-form :model="formData1" label-width="120px"> + <el-form-item label="瑙嗛鏍煎紡"> + <el-select v-model="formData1.isvideo" class="!w-240px"> + <el-option :disabled="formData1.value?.subtitlesAddStatus!=2" label="瀛楀箷瑙嗛" :value="1" /> + <el-option label="鍘熻棰�" :value="2" /> + </el-select> + </el-form-item> + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鐗囧ご瑙嗛"> + <div class="video-container"> + <video + v-if="formData1.value?.titles" + :src="formData1.value.titles" + controls + class="preview-video" + @error="handleVideoError('titles')" + ></video> + <div v-else class="no-video">鏆傛棤鐗囧ご瑙嗛</div> + </div> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鐗囧熬瑙嗛"> + <div class="video-container"> + <video + v-if="formData1.value?.trailer" + :src="formData1.value.trailer" + controls + class="preview-video" + @error="handleVideoError('trailer')" + ></video> + <div v-else class="no-video">鏆傛棤鐗囧熬瑙嗛</div> + </div> + </el-form-item> + </el-col> + </el-row> + <el-form-item> + <el-button + type="primary" + @click="hecheng" + :loading="applyingHeaderFooter" + :disabled="!formData1.value?.titles || !formData1.value?.trailer" + > + 寮�濮嬪悎鎴� + </el-button> + <span v-if="!formData1.value?.titles || !formData1.value?.trailer" class="ml-10px text-red-500"> + 璇峰厛璁剧疆鐗囧ご鍜岀墖灏捐棰� + </span> + </el-form-item> + </el-form> + </el-tab-pane> + <el-tab-pane label="棰勮涓庝笅杞�" name="preview"> + <el-row :gutter="20"> + <el-col :span="12"> + <div class="preview-section"> + <h4>瑙嗛</h4> + <div class="video-container"> + <video + v-if="formData1.value?.videoUrl || formData1.value?.previewUrl" + :src="formData1.value?.videoUrl || formData1.value?.previewUrl" + controls + class="preview-video" + ></video> + <div v-else class="no-video">鏆傛棤瑙嗛</div> + </div> + <div class="button-group"> + <el-button + type="primary" + @click="handleDownload(formData1.value?.videoUrl || formData1.value?.previewUrl, formData1.value?.courseName + '_瑙嗛')" + :disabled="!formData1.value?.videoUrl && !formData1.value?.previewUrl" + > + 涓嬭浇瑙嗛 + </el-button> + </div> + </div> + </el-col> + <el-col :span="12"> + <div class="preview-section"> + <h4>鐗囧ご鐗囧熬瑙嗛</h4> + <div class="video-container"> + <video + v-if="formData1.value?.compositeVideo" + :src="formData1.value.compositeVideo" + controls + class="preview-video" + ></video> + <div v-else class="no-video">鏆傛棤鐗囧ご鐗囧熬瑙嗛</div> + </div> + <div class="button-group"> + <el-button + type="primary" + @click="handleDownload(formData1.value?.compositeVideo, formData1.value?.courseName + '_鐗囧ご鐗囧熬瑙嗛')" + :disabled="!formData1.value?.compositeVideo" + > + 涓嬭浇鐗囧ご鐗囧熬瑙嗛 + </el-button> + </div> + </div> + </el-col> + </el-row> + </el-tab-pane> + </el-tabs> </el-dialog> + + <!-- 瑙嗛鍚堟垚閫夋嫨寮规 --> <el-dialog v-model="dialogVisible" - title="瑙嗛鍚堟垚涓�" + title="瑙嗛鍚堟垚" width="50%" > <el-form :model="formData1" label-width="120px"> - <el-form-item label="瑙嗛鏍煎紡"> + <el-form-item label="瑙嗛鏍煎紡"> <el-select v-model="formData1.isvideo"> <el-option :disabled="formData1.value.subtitlesAddStatus!=2" label="瀛楀箷瑙嗛" :value="1" /> <el-option label="鍘熻棰�" :value="2" /> @@ -347,6 +428,7 @@ import { config } from '@/config/axios/config' import {createVideo, createVideoMeger, videoMeger} from "@/api/pptTemplate"; import { ArrowDown } from '@element-plus/icons-vue' +import { ElMessageBox } from 'element-plus' const router = useRouter() const message = useMessage() @@ -377,6 +459,7 @@ const subtitleDialogVisible = ref(false) const subtitleFormRef = ref() const fileInput = ref<HTMLInputElement | null>(null) +const activeSubtitleTab = ref('setting') const subtitleForm = reactive({ videoId: null as number | null, timeThreshold: '0.05', @@ -385,13 +468,17 @@ subtitlesUrl: '', videoUrl: '', courseName: '', - subtitlesAddStatus: null + subtitlesAddStatus: null, + originalContent: '', + subtitlesStatus: null }) const generating = ref(false) const saving = ref(false) +const isSubtitleModified = ref(false) // 鐗囧ご鐗囧熬寮规鐩稿叧 const headerFooterDialogVisible = ref(false) +const activeTab = ref('setting') const headerFooterForm = reactive({ id: null as number | null, titles: '', @@ -527,14 +614,39 @@ return `${hrs > 0 ? `${hrs}鏃禶 : ''}${mins > 0 ? `${mins}鍒哷 : ''}${secs}绉抈 } -// 鎵撳紑瀛楀箷寮规 +// 澶勭悊瀛楀箷鍐呭鍙樺寲 +const handleSubtitleChange = () => { + isSubtitleModified.value = subtitleForm.content !== subtitleForm.originalContent +} + +// 淇敼鎵撳紑瀛楀箷寮圭獥鐨勫嚱鏁� const openSubtitleDialog = async (videoId: number) => { try { subtitleDialogVisible.value = true + activeSubtitleTab.value = 'setting' subtitleForm.videoId = videoId + + // 閲嶇疆琛ㄥ崟鐘舵�� + subtitleForm.content = '' + subtitleForm.originalContent = '' + subtitleForm.videoUrl = '' + subtitleForm.subtitlesUrl = '' + subtitleForm.subtitlesStatus = null + subtitleForm.subtitlesAddStatus = null + isSubtitleModified.value = false + generating.value = false + polling.value = false + const videoDetail = await pptTemplateApi.myCourseDetail(videoId) + if (!videoDetail) { + message.error('鑾峰彇瑙嗛璇︽儏澶辫触锛岃閲嶈瘯') + subtitleDialogVisible.value = false + return + } + subtitleForm.subtitlesAddStatus = videoDetail.subtitlesAddStatus + subtitleForm.subtitlesStatus = videoDetail.subtitlesStatus subtitleForm.courseName = videoDetail.courseName if (videoDetail.subtitlesAddStatus === 2) { @@ -545,7 +657,7 @@ subtitleForm.videoUrl = '' generating.value = true polling.value = true - }else { + } else { subtitleForm.videoUrl = videoDetail.videoUrl || '' generating.value = false polling.value = false @@ -561,28 +673,35 @@ if (response.ok) { const srtContent = await response.text() subtitleForm.content = srtContent + subtitleForm.originalContent = srtContent } else { subtitleForm.content = videoDetail.subtitlesContent || '' + subtitleForm.originalContent = videoDetail.subtitlesContent || '' } } catch (error) { console.error('鑾峰彇瀛楀箷鍐呭澶辫触:', error) subtitleForm.content = videoDetail.subtitlesContent || '' + subtitleForm.originalContent = videoDetail.subtitlesContent || '' } } else if (videoDetail.subtitlesContent) { subtitleForm.content = videoDetail.subtitlesContent + subtitleForm.originalContent = videoDetail.subtitlesContent } } else if (videoDetail.subtitlesStatus === 3) { generating.value = false polling.value = false subtitleForm.content = '' + subtitleForm.originalContent = '' } else if (videoDetail.subtitlesStatus === 1) { generating.value = true polling.value = true subtitleForm.content = '' - }else{ + subtitleForm.originalContent = '' + } else { generating.value = false polling.value = false } + isSubtitleModified.value = false } catch (error) { console.error('鑾峰彇瑙嗛璇︽儏澶辫触:', error) message.error('鑾峰彇瑙嗛璇︽儏澶辫触锛岃閲嶈瘯') @@ -639,6 +758,7 @@ } generating.value = true + subtitleForm.subtitlesStatus = 1 // 璁剧疆瀛楀箷鐘舵�佷负鐢熸垚涓� const params = { id: subtitleForm.videoId, @@ -667,16 +787,20 @@ if (response.ok) { const srtContent = await response.text() subtitleForm.content = srtContent + subtitleForm.originalContent = srtContent } } catch (error) { console.error('Error fetching SRT file:', error) } } else if (videoDetail.subtitlesContent) { subtitleForm.content = videoDetail.subtitlesContent + subtitleForm.originalContent = videoDetail.subtitlesContent } message.success(subtitleForm.courseName+' '+'瀛楀箷鐢熸垚鎴愬姛') + subtitleForm.subtitlesStatus = 2 // 璁剧疆瀛楀箷鐘舵�佷负宸插畬鎴� stopPolling() } else if (videoDetail.subtitlesStatus === 3) { + subtitleForm.subtitlesStatus = 3 // 璁剧疆瀛楀箷鐘舵�佷负澶辫触 stopPolling() } else if (attempts >= maxAttempts) { message.warning(subtitleForm.courseName+' '+'瀛楀箷鐢熸垚瓒呮椂锛岃绋嶅悗鎵嬪姩妫�鏌�') @@ -704,7 +828,7 @@ } } -// 淇濆瓨瀛楀箷 +// 淇敼淇濆瓨瀛楀箷鍑芥暟 const saveSubtitles = async () => { try { saving.value = true @@ -740,10 +864,8 @@ await pptTemplateApi.saveSubtitles(params) message.success('瀛楀箷淇濆瓨鎴愬姛') - subtitleDialogVisible.value = false - - // 鍒锋柊鍒楄〃 - getList() + subtitleForm.originalContent = subtitleForm.content + isSubtitleModified.value = false } catch (error) { console.error('淇濆瓨瀛楀箷澶辫触:', error) message.error(`淇濆瓨瀛楀箷澶辫触: ${error.message || '鏈煡閿欒'}`) @@ -770,7 +892,7 @@ return srtContent } -// 瀛楀箷瑙嗛鍚堟垚 +// 淇敼瀛楀箷瑙嗛鍚堟垚鍑芥暟 const downloadSubtitles = async () => { try { if (!subtitleForm.content.trim()) { @@ -778,7 +900,23 @@ return } - generating.value = true + if (isSubtitleModified.value) { + try { + await ElMessageBox.confirm( + '淇敼鐨勫瓧骞曟病鏈変繚瀛橈紝纭畾瑕佺敓鎴愯棰戝悧锛�', + '鎻愮ず', + { + confirmButtonText: '纭畾', + cancelButtonText: '鍙栨秷', + type: 'warning' + } + ) + } catch { + return + } + } + + subtitleForm.subtitlesAddStatus = 1 // 璁剧疆瀛楀箷瑙嗛鍚堟垚鐘舵�佷负杩涜涓� const obj = { id: subtitleForm.videoId } @@ -799,9 +937,7 @@ if (videoDetail.subtitlesAddStatus === 2) { message.success(subtitleForm.courseName+' '+'瀛楀箷瑙嗛鍚堟垚鎴愬姛') if (videoDetail.previewUrl) { - subtitleForm.content = '' stopPolling() - subtitleDialogVisible.value = false getList() } } else if (videoDetail.subtitlesAddStatus === 3) { @@ -829,8 +965,6 @@ console.error('瀛楀箷瑙嗛鍚堟垚澶辫触:', error) message.error(`瀛楀箷瑙嗛鍚堟垚澶辫触: ${error.message || '鏈煡閿欒'}`) stopPolling() - } finally { - generating.value = false } } @@ -844,25 +978,27 @@ } // 澶勭悊鐗囧ご鐗囧熬鎸夐挳鐐瑰嚮 -const handleHeaderFooter =async (row) => { - console.log(row) +const handleHeaderFooter = async (row) => { headerFooterForm.id = row.id - let details= await pptTemplateApi.myCourseDetail(row.id) - console.log(details) + let details = await pptTemplateApi.myCourseDetail(row.id) headerFooterForm.titles = details.titles || '' headerFooterForm.trailer = details.trailer || '' + formData1.value = details headerFooterDialogVisible.value = true + activeTab.value = 'setting' } + // 搴旂敤鐗囧ご鐗囧熬璁剧疆 const applyHeaderFooter = async () => { try { - console.log('搴旂敤鐗囧ご鐗囧熬璁剧疆:', headerFooterForm) const title = await pptTemplateApi.createVideo(headerFooterForm) - console.log('鍒涘缓瑙嗛鏍囬:', title) if (title) { message.success('鐗囧ご鐗囧熬璁剧疆鎴愬姛') - headerFooterDialogVisible.value = false - getList() + // 鍒囨崲鍒板悎鎴愯棰戞爣绛鹃〉 + activeTab.value = 'merge' + // 鏇存柊formData1鐨勫�� + const details = await pptTemplateApi.myCourseDetail(headerFooterForm.id!) + formData1.value = details } } catch (error) { console.error('鐗囧ご鐗囧熬璁剧疆鍑洪敊:', error) @@ -871,63 +1007,62 @@ 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 + 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 + message.success('瑙嗛鍚堟垚浠诲姟宸叉彁浜わ紝璇风◢鍚庢煡鐪�') 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 + } 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 + message.success('瑙嗛鍚堟垚浠诲姟宸叉彁浜わ紝璇风◢鍚庢煡鐪�') getList() } } - // loading.value = true - // - } - catch (error) { + } catch (error) { console.error(error) + message.error('瑙嗛鍚堟垚澶辫触') + } finally { + applyingHeaderFooter.value = false + } +} + +// 妫�鏌ヨ棰慤RL鏄惁鏈夋晥 + + +// 鑾峰彇瀹屾暣鐨勮棰慤RL + + +// 澶勭悊瑙嗛鍔犺浇閿欒 +const handleVideoError = (type: 'titles' | 'trailer') => { + console.error(`${type}瑙嗛鍔犺浇澶辫触`) + if (type === 'titles') { + formData1.value.titles = '' + } else { + formData1.value.trailer = '' } } @@ -945,7 +1080,7 @@ <style scoped> .textarea-wrapper { position: relative; - width: fit-content; + width: 100%; } .scroll-outside { @@ -976,4 +1111,137 @@ .el-dropdown { margin-left: 0; } + +.button-group { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 10px; +} + +:deep(.el-dialog__body) { + padding: 20px; +} + +:deep(.el-form-item__label) { + font-weight: 500; +} + +:deep(.el-button--primary.is-link) { + padding: 0 8px; +} + +:deep(.el-tabs__nav) { + margin-bottom: 20px; +} + +:deep(.el-tabs__item) { + font-size: 16px; + padding: 0 20px; +} + +:deep(.el-form-item) { + margin-bottom: 22px; +} + +:deep(.el-input.is-disabled .el-input__inner) { + background-color: #f5f7fa; + border-color: #e4e7ed; + color: #606266; +} + +.preview-section { + background: #f5f7fa; + padding: 20px; + border-radius: 4px; + height: 100%; +} + +.preview-section h4 { + margin: 0 0 15px 0; + color: #606266; +} + +.video-container { + width: 100%; + height: 200px; + background: #000; + border-radius: 4px; + overflow: hidden; + margin-bottom: 15px; + position: relative; +} + +.preview-video { + width: 100%; + height: 100%; + object-fit: contain; + background: #000; +} + +.no-video { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: #909399; + font-size: 14px; + background: #f5f7fa; +} + +.button-group { + display: flex; + justify-content: center; + gap: 10px; +} + +.ml-10px { + margin-left: 10px; +} + +.text-red-500 { + color: #f56c6c; +} + +.subtitle-dialog :deep(.el-dialog__body) { + padding: 20px; + min-height: 500px; +} + +.preview-section { + background: #f5f7fa; + padding: 20px; + border-radius: 4px; + height: 100%; + min-height: 400px; +} + +.video-container { + width: 100%; + height: 300px; + background: #000; + border-radius: 4px; + overflow: hidden; + margin-bottom: 15px; + position: relative; +} + +.preview-video { + width: 100%; + height: 100%; + object-fit: contain; + background: #000; +} + +.no-video { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: #909399; + font-size: 14px; + background: #f5f7fa; +} </style> -- Gitblit v1.9.3