11
Change-Id: Id6671597b5f501cc2c20a5c996c52c389d46938a
diff --git a/Merge/front/src/components/MediaPreview.jsx b/Merge/front/src/components/MediaPreview.jsx
new file mode 100644
index 0000000..3f0c6e2
--- /dev/null
+++ b/Merge/front/src/components/MediaPreview.jsx
@@ -0,0 +1,119 @@
+import React, { useState } from 'react'
+import VideoPreview from './VideoPreview'
+import { Play } from 'lucide-react'
+
+// 判断文件是否为视频
+const isVideoFile = (url) => {
+ if (!url) return false
+ const videoExtensions = ['.mp4', '.webm', '.ogg', '.avi', '.mov', '.wmv', '.flv', '.mkv']
+ const lowerUrl = url.toLowerCase()
+ return videoExtensions.some(ext => lowerUrl.includes(ext)) || lowerUrl.includes('video')
+}
+
+// 媒体预览组件(支持图片和视频)
+const MediaPreview = ({
+ url,
+ alt = '',
+ className = '',
+ style = {},
+ onClick = null,
+ showPlayIcon = true,
+ maxWidth = 220,
+ maxHeight = 220
+}) => {
+ const [showVideoPreview, setShowVideoPreview] = useState(false)
+
+ const handleMediaClick = () => {
+ if (isVideoFile(url)) {
+ setShowVideoPreview(true)
+ } else if (onClick) {
+ onClick(url)
+ }
+ }
+
+ const defaultStyle = {
+ maxWidth,
+ maxHeight,
+ borderRadius: 8,
+ objectFit: 'cover',
+ cursor: 'pointer',
+ ...style
+ }
+
+ if (isVideoFile(url)) {
+ return (
+ <>
+ <div style={{ position: 'relative', ...defaultStyle }} onClick={handleMediaClick}>
+ <video
+ src={url}
+ style={defaultStyle}
+ preload="metadata"
+ muted
+ />
+ {showPlayIcon && (
+ <div style={{
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ transform: 'translate(-50%, -50%)',
+ background: 'rgba(0,0,0,0.6)',
+ borderRadius: '50%',
+ padding: 12,
+ color: 'white'
+ }}>
+ <Play size={24} fill="white" />
+ </div>
+ )}
+ </div>
+
+ {/* 视频预览弹窗 */}
+ {showVideoPreview && (
+ <div
+ style={{
+ position: 'fixed',
+ zIndex: 9999,
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ background: 'rgba(0,0,0,0.8)',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 20
+ }}
+ onClick={() => setShowVideoPreview(false)}
+ >
+ <div
+ style={{
+ maxWidth: '90vw',
+ maxHeight: '90vh',
+ width: 'auto',
+ height: 'auto'
+ }}
+ onClick={(e) => e.stopPropagation()}
+ >
+ <VideoPreview
+ src={url}
+ onClose={() => setShowVideoPreview(false)}
+ style={{ borderRadius: 12, overflow: 'hidden' }}
+ />
+ </div>
+ </div>
+ )}
+ </>
+ )
+ }
+
+ return (
+ <img
+ src={url}
+ alt={alt}
+ className={className}
+ style={defaultStyle}
+ onClick={handleMediaClick}
+ />
+ )
+}
+
+export default MediaPreview