| | |
| | | </div> |
| | | |
| | | <!-- 视频预览 --> |
| | | <div v-else-if="isVideo(file)" class="video-preview"> |
| | | <video |
| | | :src="file.url" |
| | | controls |
| | | preload="metadata" |
| | | class="preview-video" |
| | | > |
| | | 您的浏览器不支持视频播放 |
| | | </video> |
| | | <div v-else-if="isVideo(file)" class="video-preview" @click="playVideo(file)"> |
| | | <div class="video-thumbnail"> |
| | | <el-image |
| | | :src="file.thumbUrl || file.url" |
| | | :alt="file.name" |
| | | fit="cover" |
| | | class="preview-image" |
| | | /> |
| | | <div class="play-overlay"> |
| | | <el-icon :size="40" class="play-icon"> |
| | | <VideoPlay /> |
| | | </el-icon> |
| | | </div> |
| | | </div> |
| | | <div class="file-info"> |
| | | <span class="file-name">{{ file.name }}</span> |
| | | <span class="file-size">{{ formatFileSize(file.fileSize) }}</span> |
| | |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | @click="downloadFile(file)" |
| | | @click="previewOrDownloadFile(file)" |
| | | class="download-btn" |
| | | > |
| | | 下载 |
| | | {{ isImage(file) || isVideo(file) ? '预览' : '下载' }} |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | |
| | | <div v-else class="no-files"> |
| | | <el-empty description="暂无提交资料" :image-size="80" /> |
| | | </div> |
| | | |
| | | <!-- 视频播放对话框 --> |
| | | <el-dialog |
| | | v-model="videoDialogVisible" |
| | | :title="currentVideoFile?.name || '视频播放'" |
| | | width="80%" |
| | | center |
| | | > |
| | | <div class="video-player-container"> |
| | | <video |
| | | v-if="currentVideoFile" |
| | | :src="currentVideoFile.url" |
| | | controls |
| | | autoplay |
| | | class="video-player" |
| | | > |
| | | 您的浏览器不支持视频播放 |
| | | </video> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed } from 'vue' |
| | | import { ElImage, ElButton, ElIcon, ElEmpty } from 'element-plus' |
| | | import { Document, Files } from '@element-plus/icons-vue' |
| | | import { computed, ref } from 'vue' |
| | | import { ElImage, ElButton, ElIcon, ElEmpty, ElDialog } from 'element-plus' |
| | | import { Document, Files, VideoPlay } from '@element-plus/icons-vue' |
| | | |
| | | const props = defineProps({ |
| | | files: { |
| | |
| | | default: () => [] |
| | | } |
| | | }) |
| | | |
| | | // 视频播放对话框 |
| | | const videoDialogVisible = ref(false) |
| | | const currentVideoFile = ref(null) |
| | | |
| | | // 图片文件URL列表(用于预览) |
| | | const imageUrls = computed(() => { |
| | |
| | | return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i] |
| | | } |
| | | |
| | | // 下载文件 |
| | | const downloadFile = (file) => { |
| | | const link = document.createElement('a') |
| | | link.href = file.url |
| | | link.download = file.name |
| | | link.target = '_blank' |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | document.body.removeChild(link) |
| | | // 播放视频 |
| | | const playVideo = (file) => { |
| | | currentVideoFile.value = file |
| | | videoDialogVisible.value = true |
| | | } |
| | | |
| | | // 预览或下载文件 |
| | | const previewOrDownloadFile = (file) => { |
| | | if (isImage(file) || isVideo(file)) { |
| | | // 图片和视频在新窗口中预览 |
| | | window.open(file.url, '_blank') |
| | | } else { |
| | | // 其他文件类型下载 |
| | | const link = document.createElement('a') |
| | | link.href = file.url |
| | | link.download = file.name |
| | | link.target = '_blank' |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | document.body.removeChild(link) |
| | | } |
| | | } |
| | | </script> |
| | | |
| | |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .preview-image, |
| | | .preview-video { |
| | | .preview-image { |
| | | width: 100%; |
| | | height: 120px; |
| | | object-fit: cover; |
| | | } |
| | | |
| | | .video-thumbnail { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 120px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .play-overlay { |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translate(-50%, -50%); |
| | | background: rgba(0, 0, 0, 0.6); |
| | | border-radius: 50%; |
| | | padding: 12px; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .play-overlay:hover { |
| | | background: rgba(0, 0, 0, 0.8); |
| | | transform: translate(-50%, -50%) scale(1.1); |
| | | } |
| | | |
| | | .play-icon { |
| | | color: white; |
| | | } |
| | | |
| | | .document-preview { |
| | |
| | | .file-document { |
| | | border-color: #E6A23C; |
| | | } |
| | | |
| | | .video-player-container { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | min-height: 300px; |
| | | } |
| | | |
| | | .video-player { |
| | | width: 100%; |
| | | max-width: 800px; |
| | | height: auto; |
| | | } |
| | | </style> |