Commit 36f6d06a by lijiabin

【需求 20331】 perf: 优化上传视频相关的内容

parent 44b3ef9d
...@@ -36,24 +36,26 @@ ...@@ -36,24 +36,26 @@
</div> </div>
<!-- 上传完成 --> <!-- 上传完成 -->
<div v-if="videoInfo && !uploading" class="upload-success"> <div v-if="videoInfo && !uploading" class="upload-success-optimized">
<div class="video-preview"> <div class="video-info-display">
<video <div class="video-icon-wrapper">
:src="videoInfo.url" <el-icon class="video-preview-icon"><IEpVideoCamera /></el-icon>
poster="@/assets/img/culture/ask.png" </div>
class="video-thumbnail" <div class="video-details-text">
muted <p class="video-name">{{ videoInfo.name }}</p>
></video> <p class="video-meta">
<div class="video-overlay"> {{ formatFileSize(videoInfo.size) }} · {{ videoInfo.duration }} ·
<el-button type="primary" size="small" @click="replaceVideo"> 重新选择 </el-button> {{ videoInfo.resolution }}
</p>
</div> </div>
</div> </div>
<div class="video-details"> <div class="video-actions">
<p class="video-name">{{ videoInfo.name }}</p> <el-button type="primary" @click="replaceVideo">
<p class="video-meta"> <el-icon class="mr-2"><IEpRefresh /></el-icon> 重新选择
{{ formatFileSize(videoInfo.size) }} · {{ videoInfo.duration }} · </el-button>
{{ videoInfo.resolution }} <el-button type="success" @click="previewVideo">
</p> <el-icon class="mr-2"><IEpView /></el-icon> 预览播放
</el-button>
</div> </div>
</div> </div>
</el-upload> </el-upload>
...@@ -71,6 +73,7 @@ ...@@ -71,6 +73,7 @@
import { uploadFile as uploadFileApi } from '@/api/common' import { uploadFile as uploadFileApi } from '@/api/common'
import type { UploadFile } from 'element-plus' import type { UploadFile } from 'element-plus'
import type { UploadVideoProps } from './types' import type { UploadVideoProps } from './types'
import { getVideoMetadata } from '@/utils'
interface VideoInfo { interface VideoInfo {
url: string url: string
...@@ -108,30 +111,6 @@ const formatFileSize = (bytes: number): string => { ...@@ -108,30 +111,6 @@ const formatFileSize = (bytes: number): string => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
} }
// 获取视频时长和分辨率
const getVideoMetadata = (file: File): Promise<{ duration: string; resolution: string }> => {
return new Promise((resolve) => {
const video = document.createElement('video')
video.preload = 'metadata'
video.onloadedmetadata = () => {
const duration = formatDuration(video.duration)
const resolution = `${video.videoWidth}x${video.videoHeight}`
URL.revokeObjectURL(video.src)
resolve({ duration, resolution })
}
video.src = URL.createObjectURL(file)
})
}
// 格式化时长
const formatDuration = (seconds: number): string => {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${secs.toString().padStart(2, '0')}`
}
// 上传前验证 // 上传前验证
const beforeUpload = (file: File): boolean => { const beforeUpload = (file: File): boolean => {
uploadError.value = '' uploadError.value = ''
...@@ -185,7 +164,7 @@ const startUpload = async () => { ...@@ -185,7 +164,7 @@ const startUpload = async () => {
console.log(data) console.log(data)
// 获取视频元数据 // 获取视频元数据
const metadata = await getVideoMetadata(currentFile.value) const metadata = await getVideoMetadata(data.filePath)
// 根据你的 API 返回结构调整 // 根据你的 API 返回结构调整
const videoData: VideoInfo = { const videoData: VideoInfo = {
...@@ -235,6 +214,11 @@ const replaceVideo = () => { ...@@ -235,6 +214,11 @@ const replaceVideo = () => {
currentFile.value = null currentFile.value = null
} }
// 预览播放
const previewVideo = () => {
window.open(videoInfo.value?.url, '_blank')
}
// 重试上传 // 重试上传
const retryUpload = () => { const retryUpload = () => {
uploadError.value = '' uploadError.value = ''
...@@ -472,4 +456,52 @@ defineExpose({ ...@@ -472,4 +456,52 @@ defineExpose({
height: 90px; height: 90px;
} }
} }
.upload-success-optimized {
display: flex;
flex-direction: column; /* Stack video info and actions vertically */
align-items: center; /* Center content horizontally */
justify-content: center;
padding: 20px 40px; /* Add some internal padding */
gap: 15px; /* Space between video info and actions */
}
.video-info-display {
display: flex;
align-items: center; /* Vertically align icon and text */
gap: 15px; /* Space between icon and text */
}
.video-icon-wrapper {
font-size: 48px; /* Larger icon size */
color: #6366f1;
}
.video-details-text {
text-align: left; /* Align text within its container */
}
.video-name {
font-size: 16px;
font-weight: bold;
color: #303133; /* Darker color for prominence */
margin-bottom: 5px;
word-break: break-all; /* Ensure long file names wrap */
}
.video-meta {
font-size: 13px;
color: #909399; /* Lighter color for secondary info */
}
.video-actions {
display: flex;
gap: 10px; /* Space between buttons */
margin-top: 10px; /* Space above buttons if stacked below video info */
}
.upload-success-optimized {
flex-direction: row;
justify-content: space-between;
}
</style> </style>
...@@ -85,3 +85,34 @@ export function jumpToArticleDetailPage({ type, id }: { type: ArticleTypeEnum; i ...@@ -85,3 +85,34 @@ export function jumpToArticleDetailPage({ type, id }: { type: ArticleTypeEnum; i
window.open(`/articleDetail/${id}`) window.open(`/articleDetail/${id}`)
} }
} }
// 根据oss视频链接获取视频元信息
export function getVideoMetadata(url: string): Promise<{
duration: string
resolution: string
}> {
return new Promise((resolve, reject) => {
const video = document.createElement('video')
video.src = url
video.preload = 'metadata'
video.addEventListener('loadedmetadata', () => {
const duration = formatDuration(video.duration)
const resolution = `${video.videoWidth}x${video.videoHeight}`
resolve({
duration,
resolution,
})
})
video.addEventListener('error', () => {
reject(new Error('视频加载失败'))
})
})
}
// 格式化视频时长
export function formatDuration(seconds: number): string {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${secs.toString().padStart(2, '0')}`
}
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
主标签 主标签
<el-tooltip content="主标签最多添加一个" placement="top"> <el-tooltip content="主标签最多添加一个" placement="top">
<el-icon class="text-gray-400 cursor-help"> <el-icon class="text-gray-400 cursor-help">
<QuestionFilled /> <IEpQuestionFilled />
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
</label> </label>
...@@ -119,7 +119,7 @@ ...@@ -119,7 +119,7 @@
副标签 副标签
<el-tooltip content="副标签最多添加3个" placement="top"> <el-tooltip content="副标签最多添加3个" placement="top">
<el-icon class="text-gray-400 cursor-help"> <el-icon class="text-gray-400 cursor-help">
<QuestionFilled /> <IEpQuestionFilled />
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
</label> </label>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment