Explorar el Código

feat(mini): 改进人才详情页视频播放功能,使用弹窗播放器

- 添加视频文件类型检测功能
- 使用 Taro Video 组件直接播放视频 URL,无需下载
- 添加视频播放弹窗状态管理
- 添加带关闭按钮的视频播放弹窗 UI
- 图片文件使用 Taro.previewImage 预览
- 文档文件保持原有下载打开逻辑

Co-Authored-By: Claude <noreply@anthropic.com>
yourname hace 1 semana
padre
commit
5635bb6e1e

+ 122 - 24
mini-ui-packages/yongren-talent-management-ui/src/pages/TalentDetail/TalentDetail.tsx

@@ -1,5 +1,5 @@
-import React, { useEffect } from 'react'
-import { View, Text, ScrollView } from '@tarojs/components'
+import React, { useEffect, useState } from 'react'
+import { View, Text, ScrollView, Video } from '@tarojs/components'
 import Taro from '@tarojs/taro'
 import { useQuery } from '@tanstack/react-query'
 import { PageContainer } from '@d8d/mini-shared-ui-components/components/page-container'
@@ -25,6 +25,10 @@ const TalentDetail: React.FC<TalentDetailProps> = () => {
   const router = Taro.useRouter()
   const talentId = router.params.id ? parseInt(router.params.id) : 0
 
+  // 视频播放器状态
+  const [showVideoPlayer, setShowVideoPlayer] = useState(false)
+  const [currentVideoUrl, setCurrentVideoUrl] = useState<string>('')
+
   // 获取人才基本信息
   const { data: talentDetail, isLoading: talentLoading, error: talentError } = useQuery({
     queryKey: ['talentDetail', talentId],
@@ -271,6 +275,28 @@ const TalentDetail: React.FC<TalentDetailProps> = () => {
     return `¥${amount.toLocaleString()}`
   }
 
+  // 判断文件类型的辅助函数
+  const getFileType = (url: string): 'image' | 'video' | 'other' => {
+    // 从 URL 中提取文件扩展名
+    const urlLower = url.toLowerCase()
+    const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg']
+    const videoExtensions = ['.mp4', '.mov', '.avi', '.mkv', '.wmv', '.flv', '.m4v']
+
+    for (const ext of imageExtensions) {
+      if (urlLower.includes(ext)) {
+        return 'image'
+      }
+    }
+
+    for (const ext of videoExtensions) {
+      if (urlLower.includes(ext)) {
+        return 'video'
+      }
+    }
+
+    return 'other'
+  }
+
   // 打开文件URL的函数
   const handleOpenFile = (url?: string, _fileName?: string) => {
     if (!url) {
@@ -285,31 +311,65 @@ const TalentDetail: React.FC<TalentDetailProps> = () => {
       // 在H5环境中使用window.open
       if (process.env.TARO_ENV === 'h5') {
         window.open(url, '_blank')
-      } else {
-        // 在小程序中使用Taro.openDocument
-        Taro.downloadFile({
-          url: url,
-          success: (res) => {
-            if (res.statusCode === 200) {
-              Taro.openDocument({
-                filePath: res.tempFilePath,
-                showMenu: true,
-                fail: (_err) => {
-                  Taro.showToast({
-                    title: '文件打开失败',
-                    icon: 'none'
-                  })
+        return
+      }
+
+      // 在小程序中根据文件类型选择不同的处理方式
+      const fileType = getFileType(url)
+
+      switch (fileType) {
+        case 'image':
+          // 图片文件使用 Taro.previewImage 预览
+          Taro.previewImage({
+            current: url,
+            urls: [url]
+          })
+          break
+
+        case 'video':
+          // 视频文件使用弹窗播放器直接播放
+          setCurrentVideoUrl(url)
+          setShowVideoPlayer(true)
+          break
+
+        case 'other':
+          // 其他文件使用 Taro.openDocument
+          Taro.downloadFile({
+            url: url,
+            success: (res) => {
+              if (res.statusCode === 200) {
+                // 从 URL 或文件名中提取文件类型
+                const urlLower = url.toLowerCase()
+                let fileType = ''
+                const docTypes = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt']
+                for (const type of docTypes) {
+                  if (urlLower.includes(type)) {
+                    fileType = type.replace('.', '')
+                    break
+                  }
                 }
+
+                Taro.openDocument({
+                  filePath: res.tempFilePath,
+                  fileType: (fileType || undefined) as Parameters<typeof Taro.openDocument>[0]['fileType'],
+                  showMenu: true,
+                  fail: (_err) => {
+                    Taro.showToast({
+                      title: '文件打开失败',
+                      icon: 'none'
+                    })
+                  }
+                })
+              }
+            },
+            fail: (_err) => {
+              Taro.showToast({
+                title: '文件下载失败',
+                icon: 'none'
               })
             }
-          },
-          fail: (_err) => {
-            Taro.showToast({
-              title: '文件下载失败',
-              icon: 'none'
-            })
-          }
-        })
+          })
+          break
       }
     } catch (_error) {
       Taro.showToast({
@@ -729,6 +789,44 @@ const TalentDetail: React.FC<TalentDetailProps> = () => {
           )}
         </ScrollView>
 
+        {/* 视频播放弹窗 */}
+        {showVideoPlayer && (
+          <View className="fixed inset-0 z-50 bg-black bg-opacity-75 flex items-center justify-center">
+            <View className="relative w-full max-w-lg mx-4">
+              {/* 关闭按钮 */}
+              <View
+                className="absolute -top-10 right-0 z-10 w-8 h-8 bg-white rounded-full flex items-center justify-center"
+                onClick={() => {
+                  setShowVideoPlayer(false)
+                  setCurrentVideoUrl('')
+                }}
+              >
+                <Text className="i-heroicons-x-mark-20-solid text-gray-700 text-lg" />
+              </View>
+              {/* 视频播放器 */}
+              <Video
+                src={currentVideoUrl}
+                controls
+                autoplay
+                loop={false}
+                muted={false}
+                initialTime={0}
+                id="video-player"
+                className="w-full rounded-lg"
+                style={{ width: '100%', height: 'auto' }}
+                onEnded={() => {
+                  // 视频播放结束后的处理(可选)
+                }}
+                onError={() => {
+                  Taro.showToast({
+                    title: '视频播放失败',
+                    icon: 'none'
+                  })
+                }}
+              />
+            </View>
+          </View>
+        )}
       </PageContainer>
   )
 }