From 044d520a74256e435e55f215060bf06bc7442d7f Mon Sep 17 00:00:00 2001
From: 康鲁杰 <60095866+KangLujie@users.noreply.github.com>
Date: 星期五, 18 四月 2025 14:39:26 +0800
Subject: [PATCH] 我的视频选择片头片尾

---
 easegen-front/src/views/myCourse/index.vue |  354 +++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 239 insertions(+), 115 deletions(-)

diff --git a/easegen-front/src/views/myCourse/index.vue b/easegen-front/src/views/myCourse/index.vue
index 9a4fe19..83b4e7c 100644
--- a/easegen-front/src/views/myCourse/index.vue
+++ b/easegen-front/src/views/myCourse/index.vue
@@ -147,7 +147,22 @@
   </ContentWrap>
 
   <!-- 瑙嗛鎾斁寮规 -->
-  <videoDialog ref="videoRef" />
+  <el-dialog
+    v-model="videoPlayDialogVisible"
+    title="瑙嗛棰勮"
+    width="60%"
+    @close="handleVideoPlayClose"
+  >
+    <div class="video-play-container">
+      <video
+        ref="currentPlayVideo"
+        v-if="currentPlayUrl"
+        :src="currentPlayUrl"
+        controls
+        class="play-video"
+      ></video>
+    </div>
+  </el-dialog>
 
   <!-- 瀛楀箷鐢熸垚寮规 -->
   <el-dialog
@@ -276,24 +291,11 @@
   <!-- 鐗囧ご鐗囧熬璁剧疆寮规 -->
   <el-dialog
     v-model="headerFooterDialogVisible"
-    title="鐗囧ご鐗囧熬璁剧疆"
+    title="鐗囧ご鐗囧熬"
     width="70%"
     @close="pauseAllVideos('headerFooter')"
   >
     <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="瑙嗛鏍煎紡">
@@ -305,49 +307,81 @@
           <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 class="video-select-container">
+                  <div class="video-grid">
+                    <div
+                      v-for="item in titlesList"
+                      :key="item.id"
+                      class="video-card"
+                      :class="{ 'is-selected': formData1.value.titles === item.url }"
+                      @click="handleTitlesSelect(item)"
+                    >
+                      <div class="video-thumbnail">
+                        <video
+                          :src="item.url"
+                          class="thumbnail-video"
+                          controls
+                        ></video>
+                      </div>
+                      <div class="video-info">
+                        <span class="video-name">{{ item.name }}</span>
+                        <el-icon v-if="formData1.value.titles === item.url" class="selected-icon"><Check /></el-icon>
+                      </div>
+                    </div>
+                  </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 class="video-select-container">
+                  <div class="video-grid">
+                    <div
+                      v-for="item in trailerList"
+                      :key="item.id"
+                      class="video-card"
+                      :class="{ 'is-selected': formData1.value.trailer === item.url }"
+                      @click="handleTrailerSelect(item)"
+                    >
+                      <div class="video-thumbnail">
+                        <video
+                          :src="item.url"
+                          class="thumbnail-video"
+                          controls
+                        ></video>
+                      </div>
+                      <div class="video-info">
+                        <span class="video-name">{{ item.name }}</span>
+                        <el-icon v-if="formData1.value.trailer === item.url" class="selected-icon"><Check /></el-icon>
+                      </div>
+                    </div>
+                  </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>
+            <div style="display: flex; width: 100%;">
+              <div style="flex: 1;">
+                <span v-if="!formData1.value?.titles || !formData1.value?.trailer" class="text-red-500">
+                  璇峰厛閫夋嫨鐗囧ご鍜岀墖灏捐棰�
+                </span>
+              </div>
+              <div style="margin-right: 165px;">
+                <el-button
+                  type="primary"
+                  @click="hecheng"
+                  :loading="applyingHeaderFooter"
+                  :disabled="!formData1.value?.titles || !formData1.value?.trailer"
+                >
+                  寮�濮嬪悎鎴�
+                </el-button>
+              </div>
+            </div>
           </el-form-item>
         </el-form>
       </el-tab-pane>
-      <el-tab-pane label="棰勮涓庝笅杞�" name="preview">
+      <el-tab-pane label="棰勮涓嬭浇" name="preview">
         <el-row :gutter="20">
           <el-col :span="12">
             <div class="preview-section">
@@ -436,9 +470,9 @@
 import axios from 'axios'
 import { config } from '@/config/axios/config'
 import {createVideo, createVideoMeger, videoMeger} from "@/api/pptTemplate";
-import { ArrowDown } from '@element-plus/icons-vue'
+import { ArrowDown, Check, VideoPlay, VideoPause } from '@element-plus/icons-vue'
 import { ElMessageBox } from 'element-plus'
-
+import { listFile } from '@/api/system/file'
 const router = useRouter()
 const message = useMessage()
 const { t } = useI18n()
@@ -492,7 +526,7 @@
 
 // 鐗囧ご鐗囧熬寮规鐩稿叧
 const headerFooterDialogVisible = ref(false)
-const activeTab = ref('setting')
+const activeTab = ref('merge')
 const headerFooterForm = reactive({
   id: null as number | null,
   titles: '',
@@ -500,16 +534,13 @@
 })
 
 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 titlesList = ref([])
+const trailerList = ref([])
+
+// 瑙嗛鎾斁鐩稿叧
+const currentPlayUrl = ref('')
+const videoRefs = ref<HTMLVideoElement[]>([])
+
 // 鑾峰彇瑙嗛鍒楄〃
 const getList = async () => {
   loading.value = true
@@ -1005,6 +1036,31 @@
   polling.value = false
 }
 
+// 鑾峰彇鐗囧ご鐗囧熬鍒楄〃
+const getTitlesTrailerList = async () => {
+  try {
+    // 鑾峰彇鐗囧ご鍒楄〃
+    const titlesRes = await listFile({ type: 1 })
+    titlesList.value = titlesRes.list || []
+
+    // 鑾峰彇鐗囧熬鍒楄〃
+    const trailerRes = await listFile({ type: 2 })
+    trailerList.value = trailerRes.list || []
+  } catch (error) {
+    console.error('鑾峰彇鐗囧ご鐗囧熬鍒楄〃澶辫触:', error)
+  }
+}
+
+// 澶勭悊鐗囧ご閫夋嫨
+const handleTitlesSelect = (item) => {
+  formData1.value.titles = item.url
+}
+
+// 澶勭悊鐗囧熬閫夋嫨
+const handleTrailerSelect = (item) => {
+  formData1.value.trailer = item.url
+}
+
 // 澶勭悊鐗囧ご鐗囧熬鎸夐挳鐐瑰嚮
 const handleHeaderFooter = async (row) => {
   headerFooterForm.id = row.id
@@ -1013,7 +1069,8 @@
   headerFooterForm.trailer = details.trailer || ''
   formData1.value = details
   headerFooterDialogVisible.value = true
-  activeTab.value = 'setting'
+  activeTab.value = 'merge'
+  await getTitlesTrailerList()
 }
 
 // 搴旂敤鐗囧ご鐗囧熬璁剧疆
@@ -1041,6 +1098,16 @@
 const hecheng = async () => {
   try {
     applyingHeaderFooter.value = true
+
+    // 1. 鍏堜繚瀛橀厤缃�
+    const saveParams = {
+      id: headerFooterForm.id,
+      titles: formData1.value.titles,
+      trailer: formData1.value.trailer
+    }
+    await pptTemplateApi.createVideo(saveParams)
+
+    // 2. 鍐嶈皟鐢ㄥ悎鎴愭帴鍙�
     let obj = {}
     if (formData1.isvideo == '2') {
       obj = {
@@ -1108,6 +1175,14 @@
 onMounted(() => {
   getList()
 })
+
+// 鎾斁棰勮
+const playPreview = (type: 'titles' | 'trailer') => {
+  const video = type === 'titles' ? formData1.value.titles : formData1.value.trailer
+  if (video) {
+    window.open(video, '_blank')
+  }
+}
 </script>
 
 <style scoped>
@@ -1188,6 +1263,7 @@
   padding: 20px;
   border-radius: 4px;
   height: 100%;
+  min-height: 500px;
 }
 
 .preview-section h4 {
@@ -1197,7 +1273,7 @@
 
 .video-container {
   width: 100%;
-  height: 200px;
+  height: 400px;
   background: #000;
   border-radius: 4px;
   overflow: hidden;
@@ -1223,61 +1299,109 @@
   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;
-}
 .video-container1{
-  height: 490px !important;
+  height: 700px !important;
+}
+
+.video-select-container {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.video-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
+  gap: 20px;
+  padding: 16px;
+  background: #f5f7fa;
+  border-radius: 8px;
+  max-height: 400px;
+  overflow-y: auto;
+}
+
+.video-card {
+  position: relative;
+  background: #fff;
+  border-radius: 8px;
+  overflow: hidden;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+
+.video-card.is-selected {
+  box-shadow: 0 4px 16px 0 rgba(64, 158, 255, 0.2);
+}
+
+.video-thumbnail {
+  position: relative;
+  width: 100%;
+  padding-top: 56.25%; /* 16:9 姣斾緥 */
+  background: #000;
+  overflow: hidden;
+}
+
+.thumbnail-video {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.video-info {
+  padding: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background: #fff;
+}
+
+.video-name {
+  flex: 1;
+  font-size: 14px;
+  color: #303133;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  margin-right: 8px;
+}
+
+.selected-icon {
+  color: var(--el-color-primary);
+  font-size: 18px;
+  flex-shrink: 0;
+}
+
+/* 鑷畾涔夋粴鍔ㄦ潯鏍峰紡 */
+.video-grid::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+
+.video-grid::-webkit-scrollbar-thumb {
+  background: #c0c4cc;
+  border-radius: 3px;
+}
+
+.video-grid::-webkit-scrollbar-track {
+  background: #f5f7fa;
+  border-radius: 3px;
+}
+
+.video-play-container {
+  width: 100%;
+  background: #000;
+  border-radius: 4px;
+  overflow: hidden;
+  aspect-ratio: 16/9;
+}
+
+.play-video {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
 }
 </style>

--
Gitblit v1.9.3