提交 d5750400 authored 作者: lidongxu's avatar lidongxu

test(inspectiontask): 测试:勤策移动端_售点稽查_视频播放

上级 229c1f30
......@@ -67,11 +67,10 @@
<!-- 自定义预览内容 -->
<template #preview-cover="{ url, index }">
<div class="preview-container"
@click.stop>
<!-- 图片预览 -->
<van-image v-if="getFileType(url) === 'image'"
<van-image v-if="getMediaType(url) === 'image'"
:src="url"
alt=""
class="preview-media"
......@@ -79,29 +78,31 @@
@click="previewImage(url)" />
<!-- 视频预览 -->
<video v-else-if="getFileType(url) === 'video'"
:src="url"
ref="videoRef"
alt=""
muted
autoplay
playsinline
preload="auto"
class="preview-media"
@loadeddata="onVideoLoadedData({ value: videoRef.value, url: url })"
@error="onVideoError(url)" />
<div class="play-hint"
@click.stop="showVideoFullscreen(url)">
<div class="video-wrap"
v-else-if="getMediaType(url) === 'video'">
<video :src="url"
alt=""
ref="videoRef"
muted
autoplay
playsinline
preload="auto"
class="preview-media"
@loadeddata="handleVideoLoaded" />
<div class="play-hint"
@click.stop="showVideoFullscreen(url)">
</div>
</div>
<!-- 删除按钮 -->
<van-icon name="clear"
class="delete-icon"
@click.stop="deleteCommitStorePhotos" />
<!-- 类型标识 -->
<span v-if="getFileType(url) === 'video'"
<span v-if="getMediaType(url) === 'video'"
class="video-tag">
视频
</span>
......@@ -223,29 +224,6 @@
size="40"
text-color="#f12528">加载中...</van-loading>
</van-overlay>
<!-- 视频全屏预览 Dialog -->
<!-- <van-dialog v-model:show="videoDialogVisible"
title="视频预览"
:show-cancel-button="false"
:show-confirm-button="false"
:before-close="closeVideoFullscreen"
class="fullscreen-video-dialog"
@closed="closeVideoFullscreen">
<div class="video-container">
<div class="close-button"
@click.stop="videoDialogVisible = false">×</div>
<video id="fullscreen-video"
v-if="currentVideo"
:src="currentVideo"
alt=""
controls
autoplay
class="fullscreen-video"
@click="handleVideoClick" />
</div>
</van-dialog> -->
</div>
</template>
......@@ -262,9 +240,7 @@ import { getFileTypeExt, getMediaType } from '@/utils'
// 引入必要的组件
import { showImagePreview } from 'vant';
const previewImage = (url) => {
showImagePreview([url]);
}
const router = useRouter()
const route = useRoute()
......@@ -448,10 +424,6 @@ const commitStorePhotosRead = async (file) => {
url: pictureUrl,
status: 'done'
}]
// 上传完成后,为视频生成海报
if (getFileType(pictureUrl) === 'video') {
generateVideoPoster(pictureUrl);
}
await createInspectionTaskAPI({
storeCode: form.storeCode,
storeName: form.storeName,
......@@ -473,256 +445,69 @@ const deleteCommitStorePhotos = async () => {
if (!route.query.storePicture) form.storePicture = ""
showNotify({ type: 'success', message: '门头照,删除成功' })
}
// 文件大小限制
const onOversize = (file) => {
showNotify({ type: 'danger', message: '文件大小不能超过 5 MB' })
}
const getFileType = (url) => {
return getMediaType(url)
// 图片预览
const previewImage = (url) => {
showImagePreview({
images: [url],
})
}
// // 判断是否为视频文件
// isVideo(file) {
// return file.type && file.type.startsWith('video/');
// },
// 视频拍照
// 视频全屏预览相关状态
const videoDialogVisible = ref(false);
const currentVideo = ref(null);
// 显示视频全屏预览
const videoRef = ref(null);
const isPlaying = ref(false);
// const showVideoFullscreen = async (url) => {
// console.log('播放视频')
// const video = videoRef.value;
// if (!video) return;
// try {
// // 控制播放/暂停
// if (video.paused) {
// await video.play();
// isPlaying.value = true;
// } else {
// video.pause();
// isPlaying.value = false;
// }
// 视频相关状态
const videoRef = ref(null)
const isPlaying = ref(true)
// 加载完第一帧暂停
const handleVideoLoaded = () => {
isPlaying.value = false
videoRef.value.pause()
}
// // 请求全屏(跨浏览器兼容)
// if (!document.fullscreenElement) {
// // 尝试标准API和各种浏览器前缀
// if (video.requestFullscreen) {
// await video.requestFullscreen().catch(err => {
// console.error('标准全屏API失败:', err);
// });
// }
// // iOS Safari兼容
// else if (video.webkitEnterFullscreen) {
// // iOS 12及以下版本专用API
// video.webkitEnterFullscreen();
// }
// else if (video.webkitRequestFullscreen) {
// await video.webkitRequestFullscreen().catch(err => {
// console.error('WebKit全屏API失败:', err);
// });
// }
// // 如果所有全屏API都失败,至少确保视频可以播放
// }
// } catch (err) {
// console.error('视频操作失败:', err);
// // 失败时提供降级体验
// try {
// await video.play();
// isPlaying.value = true;
// } catch (innerErr) {
// console.error('降级播放也失败:', innerErr);
// }
// }
// };
// 视频相关状态
const videoPosters = ref({});
const videoLoadingStatus = ref({}); // 跟踪每个视频的加载状态
const isWebView = ref(false);
// 组件挂载时检测环境
onMounted(() => {
detectEnvironment();
// 为已有的视频URL生成海报图
if (form.commitStorePicture && form.commitStorePicture.length > 0) {
form.commitStorePicture.forEach(item => {
if (item.url && getFileType(item.url) === 'video') {
generateVideoPoster(item.url);
}
});
}
});
// 检测是否在webView中
const detectEnvironment = () => {
// 检测是否在iOS设备上
const isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
// 检测是否在webView中 - 可以根据实际项目中的webView特征调整
// 这里使用了一些常见的webView特征检测方法
const isInWebView = () => {
// iOS webView检测
if (isiOS) {
// 检查是否存在UIWebView特有的属性
const hasUIWebViewProperty = typeof navigator.standalone !== 'undefined' && !navigator.standalone;
// 检查userAgent中是否包含特定App的标识
const hasCustomUserAgent = /AppName|CustomWebView/i.test(navigator.userAgent);
return hasUIWebViewProperty || hasCustomUserAgent;
}
return false;
};
isWebView.value = isInWebView();
};
// 生成视频海报图
const generateVideoPoster = async (videoUrl) => {
// 避免重复生成
if (videoPosters.value[videoUrl] || videoLoadingStatus.value[videoUrl]) {
return;
}
// 标记为加载中
videoLoadingStatus.value[videoUrl] = true;
try {
// 创建一个临时video元素用于获取第一帧
const tempVideo = document.createElement('video');
tempVideo.src = videoUrl;
tempVideo.muted = true;
tempVideo.preload = 'metadata';
// 等待视频元数据加载完成
await new Promise((resolve, reject) => {
tempVideo.onloadedmetadata = resolve;
tempVideo.onerror = reject;
// 设置超时,防止加载过久
setTimeout(() => reject(new Error('Video metadata load timeout')), 5000);
});
// 设置当前时间为0.1秒(有时第0秒是黑屏)
tempVideo.currentTime = 0.1;
// 等待视频帧加载完成
await new Promise((resolve, reject) => {
tempVideo.onseeked = resolve;
tempVideo.onerror = reject;
setTimeout(() => reject(new Error('Video frame seek timeout')), 3000);
});
// 使用canvas绘制第一帧
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸为视频的原始尺寸或适合预览的尺寸
const targetWidth = 300; // 可以根据需要调整
const aspectRatio = tempVideo.videoHeight / tempVideo.videoWidth;
canvas.width = targetWidth;
canvas.height = Math.floor(targetWidth * aspectRatio);
// 绘制视频帧到canvas
ctx.drawImage(tempVideo, 0, 0, canvas.width, canvas.height);
// 转换为图片URL
const posterUrl = canvas.toDataURL('image/jpeg', 0.9); // 0.9是压缩质量
// 缓存海报图
videoPosters.value[videoUrl] = posterUrl;
// 清理临时资源
tempVideo.src = '';
} catch (error) {
console.warn('生成视频海报失败,使用默认海报:', error);
// 生成一个默认的占位海报图
videoPosters.value[videoUrl] = generateDefaultVideoPoster();
} finally {
// 标记为加载完成
videoLoadingStatus.value[videoUrl] = false;
}
};
// 生成默认的视频占位海报
const generateDefaultVideoPoster = () => {
// 创建一个简单的SVG作为默认海报
return 'data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22 width%3D%22300%22 height%3D%22170%22%3E%3Crect width%3D%22100%25%22 height%3D%22100%25%22 fill%3D%22%23222%22%2F%3E%3Ccircle cx%3D%22150%22 cy%3D%2285%22 r%3D%2240%22 fill%3D%22%23444%22%2F%3E%3Cpath d%3D%22M130 65 l40 20 l-40 20 z%22 fill%3D%22%23fff%22%2F%3E%3Ctext x%3D%22150%22 y%3D%22140%22 font-family%3D%22Arial%22 font-size%3D%2214%22 fill%3D%22%23999%22 text-anchor%3D%22middle%22%3E视频预览%3C%2Ftext%3E%3C%2Fsvg%3E';
};
// 获取视频海报图(修改之前的实现)
const getVideoPoster = (url) => {
// 如果已经生成了海报图,直接返回
if (videoPosters.value[url]) {
return videoPosters.value[url];
}
// 如果正在生成中,返回一个临时占位符
if (videoLoadingStatus.value[url]) {
return generateDefaultVideoPoster();
}
// onMounted(() => {
// detectEnvironment();
// });
// // 检测是否在webView中
// const detectEnvironment = () => {
// // 检测是否在iOS设备上
// const isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
// // 检测是否在webView中 - 可以根据实际项目中的webView特征调整
// // 这里使用了一些常见的webView特征检测方法
// const isInWebView = () => {
// // iOS webView检测
// if (isiOS) {
// // 检查是否存在UIWebView特有的属性
// const hasUIWebViewProperty = typeof navigator.standalone !== 'undefined' && !navigator.standalone;
// // 检查userAgent中是否包含特定App的标识
// const hasCustomUserAgent = /AppName|CustomWebView/i.test(navigator.userAgent);
// return hasUIWebViewProperty || hasCustomUserAgent;
// }
// return false;
// };
// 否则开始生成海报图
generateVideoPoster(url);
// isWebView.value = isInWebView();
// };
// 立即返回默认海报,生成完成后会自动更新
return generateDefaultVideoPoster();
};
// 视频加载错误处理
const onVideoError = (url) => {
console.error('视频加载错误:', url);
// 设置默认海报图
if (!videoPosters.value[url]) {
videoPosters.value[url] = generateDefaultVideoPoster();
}
// 重置加载状态
videoLoadingStatus.value[url] = false;
};
// 修改onVideoLoadedData函数以接收更多参数
const onVideoLoadedData = ({value: video, url}) => {
if (!video) return;
// 对于非webView环境,可以考虑预加载视频的第一帧作为海报
if (!isWebView.value) {
try {
// 尝试获取视频的第一帧作为海报图
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = video.videoWidth || 300;
canvas.height = video.videoHeight || 170;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
// 将canvas转换为图片URL并缓存
const posterUrl = canvas.toDataURL('image/jpeg');
videoPosters.value[url] = posterUrl;
video.poster = posterUrl;
} catch (error) {
console.error('生成视频海报失败:', error);
}
}
// 如果是webView环境,确保视频不会自动播放
if (isWebView.value) {
video.pause();
}
};
// 修改showVideoFullscreen函数,添加环境检测逻辑
const showVideoFullscreen = async (url) => {
console.log('播放视频');
const video = videoRef.value;
if (!video) return;
try {
// 先尝试播放视频
if (video.paused) {
await video.play();
isPlaying.value = true;
} else {
video.pause();
isPlaying.value = false;
}
await video.play();
// 然后尝试全屏(跨浏览器兼容)
if (!document.fullscreenElement) {
......@@ -774,26 +559,6 @@ const requestFullscreen = (element) => {
});
};
// 关闭视频全屏预览
const closeVideoFullscreen = () => {
videoDialogVisible.value = false;
// 确保视频停止播放
const videoElement = document.getElementById('fullscreen-video');
if (videoElement) {
videoElement.pause();
}
};
// 处理视频点击事件
const handleVideoClick = (event) => {
// 判断点击的是否是视频控件区域
// 当点击视频控件时,event.target 会指向具体的控件元素而不是 video 标签本身
if (event.target === event.currentTarget) {
// 只有点击视频播放区域(非控件)才切换播放/暂停状态
toggleVideoPlayback();
}
};
/*************** 渠道类型 ***************/
const typeOptions = ref(typeOption) // 渠道类型
const showTypePopup = ref(false)
......@@ -1020,13 +785,13 @@ const deleteLongTimePictureArr = async (file, { name, index }) => {
}
::v-deep(.van-uploader__file) {
/* .van-badge__wrapper {
.van-badge__wrapper {
display: none;
}
.van-ellipsis {
display: none;
} */
}
}
.upload-text {
......@@ -1046,13 +811,20 @@ const deleteLongTimePictureArr = async (file, { name, index }) => {
border-radius: 8px;
overflow: hidden;
.play-hint {
position: absolute;
left: 0;
top: 0;
.video-wrap {
width: 100%;
height: 100%;
.play-hint {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
}
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论