| | |
| | | <text class="popup-title">查看附件</text> |
| | | </view> |
| | | |
| | | <view class="upload-container"> |
| | | <scroll-view |
| | | class="upload-container" |
| | | scroll-y="true" |
| | | :enable-back-to-top="true" |
| | | :scroll-with-animation="true" |
| | | > |
| | | <view class="form-container"> |
| | | <view class="title">巡检附件</view> |
| | | |
| | |
| | | :src="item" |
| | | mode="aspectFill" |
| | | class="image-preview" |
| | | :lazy-load="true" |
| | | :data-index="index" |
| | | @error="handleImageError" |
| | | @load="handleImageLoad" |
| | | /> |
| | | <view v-if="imageLoadingStates[index]" class="image-loading"> |
| | | <u-loading-icon mode="spinner" color="#409eff" /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | v-for="(videoUrl, index) in beforeProductionVideos" |
| | | :key="index" |
| | | class="video-item" |
| | | @click="playVideo(videoUrl, index)" |
| | | @click="playVideo(`video_${index}`, videoUrl)" |
| | | > |
| | | <video |
| | | <image |
| | | :src="videoUrl" |
| | | mode="aspectFill" |
| | | class="video-thumbnail" |
| | | :poster="videoUrl" |
| | | :controls="false" |
| | | :show-center-play-btn="true" |
| | | @play="onVideoPlay" |
| | | /> |
| | | <video |
| | | :id="`video_${index}`" |
| | | :src="videoUrl" |
| | | class="hidden-video" |
| | | ></video> |
| | | <view class="video-overlay"> |
| | | <u-icon name="play-circle-fill" size="40" color="#fff"></u-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 视频播放弹窗 --> |
| | | <u-popup |
| | | :show="showVideoPlayer" |
| | | mode="center" |
| | | width="100%" |
| | | height="100%" |
| | | :closeable="true" |
| | | @close="closeVideoPlayer" |
| | | :safeAreaInsetBottom="false" |
| | | > |
| | | <view class="video-player-container"> |
| | | <video |
| | | v-if="currentVideoUrl" |
| | | :src="currentVideoUrl" |
| | | class="video-player" |
| | | :controls="true" |
| | | :show-center-play-btn="true" |
| | | :enable-play-gesture="true" |
| | | :show-fullscreen-btn="true" |
| | | :enable-progress-gesture="true" |
| | | :object-fit="'contain'" |
| | | @fullscreenchange="onFullscreenChange" |
| | | ></video> |
| | | </view> |
| | | </u-popup> |
| | | |
| | | <!-- 空状态 --> |
| | | <view v-if="beforeProductionImgs.length === 0 && beforeProductionVideos.length === 0" class="empty-state"> |
| | |
| | | ></u-empty> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </u-popup> |
| | | </view> |
| | |
| | | const beforeProductionImgs = ref([]) |
| | | // 视频数组 |
| | | const beforeProductionVideos = ref([]) |
| | | // 视频播放器 |
| | | const showVideoPlayer = ref(false) |
| | | const currentVideoUrl = ref('') |
| | | // 图片加载状态 |
| | | const imageLoadingStates = ref({}) |
| | | |
| | | // 打开弹窗并加载数据 |
| | | const openDialog = async (row) => { |
| | |
| | | |
| | | beforeProductionImgs.value = beforeImgs |
| | | beforeProductionVideos.value = beforeVids |
| | | |
| | | // 初始化图片加载状态 |
| | | beforeProductionImgs.value.forEach((_, index) => { |
| | | imageLoadingStates.value[index] = true |
| | | }) |
| | | |
| | | console.log('处理后的图片URLs:', beforeProductionImgs.value) |
| | | console.log('处理后的视频URLs:', beforeVids) |
| | | |
| | | dialogVisitable.value = true |
| | | } |
| | | |
| | | // 图片加载错误处理 |
| | | const handleImageError = (e) => { |
| | | console.error('图片加载失败:', e) |
| | | const index = e.target.dataset?.index |
| | | if (index !== undefined) { |
| | | imageLoadingStates.value[index] = false |
| | | } |
| | | } |
| | | |
| | | // 图片加载成功处理 |
| | | const handleImageLoad = (e) => { |
| | | const index = e.target.dataset?.index |
| | | if (index !== undefined) { |
| | | imageLoadingStates.value[index] = false |
| | | } |
| | | } |
| | | |
| | | // 预览图片 |
| | |
| | | } |
| | | |
| | | // 播放视频 |
| | | const playVideo = (url, index) => { |
| | | currentVideoUrl.value = url |
| | | showVideoPlayer.value = true |
| | | } |
| | | |
| | | // 关闭视频播放器 |
| | | const closeVideoPlayer = () => { |
| | | showVideoPlayer.value = false |
| | | currentVideoUrl.value = '' |
| | | const playVideo = (videoId, url) => { |
| | | // 创建video context并进入全屏 |
| | | setTimeout(() => { |
| | | try { |
| | | const videoContext = uni.createVideoContext(videoId) |
| | | console.log('视频上下文创建成功:', videoContext, 'videoId:', videoId) |
| | | // 先播放视频 |
| | | videoContext.play() |
| | | // 然后进入全屏 |
| | | setTimeout(() => { |
| | | videoContext.requestFullScreen({ |
| | | direction: 90 // 横屏全屏 |
| | | }) |
| | | }, 100) |
| | | } catch (error) { |
| | | console.error('创建视频上下文或进入全屏失败:', error) |
| | | uni.showToast({ |
| | | title: '播放失败', |
| | | icon: 'error' |
| | | }) |
| | | } |
| | | }, 100) |
| | | } |
| | | |
| | | // 视频播放事件 |
| | | const onVideoPlay = () => { |
| | | // 可以在这里处理播放事件 |
| | | } |
| | | |
| | | // 全屏变化事件 |
| | | const onFullscreenChange = (e) => { |
| | | console.log('全屏状态变化:', e) |
| | | // 如果退出全屏,可以选择关闭弹窗 |
| | | if (e.detail && e.detail.fullScreen === false) { |
| | | // 可以选择保持弹窗打开或关闭 |
| | | } |
| | | } |
| | | |
| | | // 表单关闭方法 |
| | |
| | | if (url.startsWith('http://') || url.startsWith('https://')) { |
| | | return url |
| | | } |
| | | // 否则添加基础域名 |
| | | return `https://nj477vg8876.vicp.fun${url.startsWith('/') ? '' : '/'}${url}` |
| | | |
| | | // 处理反斜杠路径格式,如 "\\zd\\prod\\file\\xxx.jpg" |
| | | let formattedUrl = url |
| | | // 将反斜杠转换为正斜杠 |
| | | formattedUrl = formattedUrl.replace(/\\/g, '/') |
| | | // 确保以 / 开头 |
| | | if (!formattedUrl.startsWith('/')) { |
| | | formattedUrl = '/' + formattedUrl |
| | | } |
| | | |
| | | // 添加基础域名 |
| | | const baseUrl = 'https://nj477vg8876.vicp.fun' |
| | | const fullUrl = `${baseUrl}${formattedUrl}` |
| | | console.log('格式化URL:', url, '->', fullUrl) |
| | | return fullUrl |
| | | } |
| | | |
| | | // 处理每一类数据:分离图片和视频 |
| | |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .popup-header { |
| | |
| | | |
| | | .upload-container { |
| | | flex: 1; |
| | | height: 0; |
| | | min-height: 0; |
| | | padding: 20px; |
| | | overflow-y: auto; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .form-container { |
| | |
| | | |
| | | .media-section { |
| | | margin-bottom: 30px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .section-title { |
| | |
| | | .image-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | background-color: #f5f5f5; |
| | | display: block; |
| | | } |
| | | |
| | | .image-loading { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: rgba(255, 255, 255, 0.8); |
| | | } |
| | | |
| | | .video-grid { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 15px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .video-item { |
| | | width: 160px; |
| | | height: 90px; |
| | | width: 300rpx; |
| | | height: 190rpx; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | position: relative; |
| | | background-color: #000; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .video-thumbnail { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | display: block; |
| | | } |
| | | |
| | | .video-overlay { |
| | | .hidden-video { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | background-color: rgba(0, 0, 0, 0.3); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | top: -9999px; |
| | | left: -9999px; |
| | | width: 1px; |
| | | height: 1px; |
| | | opacity: 0; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .video-player-container { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #000; |
| | | position: relative; |
| | | } |
| | | |
| | | .video-player { |
| | | width: 100%; |
| | | height: 100%; |
| | | max-width: 100vw; |
| | | max-height: 100vh; |
| | | } |
| | | |
| | | .empty-state { |