| | |
| | | |
| | | <!-- 视频预览 --> |
| | | <div v-else-if="isVideo(media)" class="media-preview"> |
| | | <video :src="media.url" class="media-video" controls></video> |
| | | <div class="video-thumbnail-container" @click="playVideo(media)"> |
| | | <img |
| | | v-if="media.thumbUrl || media.fullThumbUrl" |
| | | :src="media.thumbUrl || media.fullThumbUrl" |
| | | class="video-thumbnail" |
| | | /> |
| | | <div v-else class="video-placeholder"> |
| | | <span>视频缩略图</span> |
| | | </div> |
| | | <div class="video-play-overlay"> |
| | | <div class="video-play-button"> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> |
| | | <path d="M8 5v14l11-7z"/> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="media-info"> |
| | | <div class="media-name">{{ media.name }}</div> |
| | | <div class="media-actions"> |
| | |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Plus } from '@element-plus/icons-vue' |
| | | import { CarouselApi } from '@/api/carousel' |
| | | import { getMediasByTarget, deleteMedia, uploadFile } from '@/api/media' |
| | | import { getMediasByTarget, deleteMedia, uploadFile, uploadVideoWithThumbnail } from '@/api/media' |
| | | import { isVideoFile } from '@/utils/video.js' |
| | | import { MediaTargetType } from '@/constants/mediaTargetType' |
| | | |
| | | const props = defineProps({ |
| | | modelValue: Boolean, |
| | |
| | | try { |
| | | console.log('=== 加载轮播图媒体 ==='); |
| | | console.log('轮播图ID:', data.id); |
| | | const medias = await getMediasByTarget(4, parseInt(data.id)) |
| | | const medias = await getMediasByTarget(MediaTargetType.CAROUSEL, parseInt(data.id)) |
| | | console.log('获取到的媒体列表:', medias); |
| | | |
| | | // 转换媒体数据格式,标记为已存在的文件 |
| | |
| | | return false |
| | | } |
| | | |
| | | // 播放视频 |
| | | const playVideo = (media) => { |
| | | const videoUrl = media.url || media.fullUrl |
| | | if (videoUrl) { |
| | | // 在新窗口中打开视频 |
| | | window.open(videoUrl, '_blank') |
| | | } else { |
| | | ElMessage.warning('视频文件不存在') |
| | | } |
| | | } |
| | | |
| | | // 处理媒体文件上传 |
| | | const handleMediaFileUpload = async (carouselId) => { |
| | | console.log('=== 开始上传媒体文件 ==='); |
| | |
| | | try { |
| | | console.log('上传文件:', media.name); |
| | | |
| | | // 上传文件 |
| | | const uploadResult = await uploadFile(media.file); |
| | | console.log('上传结果:', uploadResult); |
| | | let uploadResult; |
| | | let thumbnailPath = null; |
| | | |
| | | // 检查是否为视频文件 |
| | | if (isVideoFile(media.file)) { |
| | | console.log('检测到视频文件,开始处理视频和缩略图...'); |
| | | |
| | | // 使用视频专用上传函数 |
| | | const videoResult = await uploadVideoWithThumbnail(media.file); |
| | | uploadResult = videoResult.video; |
| | | thumbnailPath = videoResult.thumbnail.path; |
| | | |
| | | console.log('视频和缩略图上传完成:', { |
| | | video: uploadResult, |
| | | thumbnail: videoResult.thumbnail |
| | | }); |
| | | } else { |
| | | // 普通文件上传 |
| | | uploadResult = await uploadFile(media.file); |
| | | console.log('文件上传结果:', uploadResult); |
| | | } |
| | | |
| | | if (uploadResult.success) { |
| | | // 保存媒体信息到数据库 |
| | | await CarouselApi.saveMedia({ |
| | | const mediaData = { |
| | | name: uploadResult.fileName, |
| | | path: uploadResult.path, |
| | | fileSize: uploadResult.fileSize, |
| | | fileExt: uploadResult.fileName.split('.').pop() || 'jpg', |
| | | mediaType: isVideo(media) ? 2 : 1, // 1表示图片,2表示视频 |
| | | targetType: 4, // 4表示轮播图 |
| | | targetType: MediaTargetType.CAROUSEL, // 轮播图 |
| | | targetId: parseInt(carouselId) |
| | | }); |
| | | }; |
| | | |
| | | // 如果是视频文件,添加缩略图路径 |
| | | if (thumbnailPath) { |
| | | mediaData.thumbPath = thumbnailPath; |
| | | console.log('添加缩略图路径:', thumbnailPath); |
| | | } |
| | | |
| | | await CarouselApi.saveMedia(mediaData); |
| | | |
| | | // 标记为已上传 |
| | | media.uploaded = true; |
| | | media.url = uploadResult.fullUrl; |
| | | if (thumbnailPath) { |
| | | media.thumbnailUrl = thumbnailPath; |
| | | } |
| | | console.log('文件上传并保存成功:', media.name); |
| | | } |
| | | } catch (error) { |
| | |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .video-thumbnail-container { |
| | | position: relative; |
| | | width: 200px; |
| | | height: 120px; |
| | | cursor: pointer; |
| | | border-radius: 4px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .video-thumbnail { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .video-placeholder { |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #f0f0f0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | border-radius: 4px; |
| | | color: #999; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .video-play-overlay { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background: rgba(0, 0, 0, 0.3); |
| | | opacity: 0; |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | |
| | | .video-thumbnail-container:hover .video-play-overlay { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .video-play-button { |
| | | width: 48px; |
| | | height: 48px; |
| | | background: rgba(255, 255, 255, 0.9); |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: #333; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .video-play-button:hover { |
| | | background: rgba(255, 255, 255, 1); |
| | | transform: scale(1.1); |
| | | } |
| | | |
| | | .file-icon { |
| | | font-size: 48px; |
| | | margin-bottom: 8px; |