| | |
| | | <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="previewVideo(videoUrl)" |
| | | @click="playVideo(`video_${index}`, videoUrl)" |
| | | > |
| | | <view class="video-preview"> |
| | | <u-icon name="play-circle-fill" size="40" color="#fff"></u-icon> |
| | | </view> |
| | | <view class="video-tip">点击播放</view> |
| | | <image |
| | | :src="videoUrl" |
| | | mode="aspectFill" |
| | | class="video-thumbnail" |
| | | /> |
| | | <video |
| | | :id="`video_${index}`" |
| | | :src="videoUrl" |
| | | class="hidden-video" |
| | | ></video> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | ></u-empty> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </u-popup> |
| | | </view> |
| | |
| | | const beforeProductionImgs = ref([]) |
| | | // 视频数组 |
| | | const beforeProductionVideos = 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 previewVideo = (url) => { |
| | | uni.previewVideo({ |
| | | sources: [{ |
| | | src: url |
| | | }], |
| | | fail: (err) => { |
| | | console.error('视频预览失败:', err) |
| | | // 播放视频 |
| | | 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: '视频预览失败', |
| | | title: '播放失败', |
| | | icon: 'error' |
| | | }) |
| | | } |
| | | }) |
| | | }, 100) |
| | | } |
| | | |
| | | // 视频播放事件 |
| | | const onVideoPlay = () => { |
| | | // 可以在这里处理播放事件 |
| | | } |
| | | |
| | | // 表单关闭方法 |
| | |
| | | // 重置数据 |
| | | beforeProductionImgs.value = [] |
| | | beforeProductionVideos.value = [] |
| | | } |
| | | |
| | | // 处理URL,添加基础域名 |
| | | function formatUrl(url) { |
| | | if (!url) return '' |
| | | // 如果已经是完整URL,直接返回 |
| | | if (url.startsWith('http://') || url.startsWith('https://')) { |
| | | return 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 |
| | | } |
| | | |
| | | // 处理每一类数据:分离图片和视频 |
| | |
| | | const videos = [] |
| | | |
| | | items.forEach(item => { |
| | | const fileUrl = item.url || item.downloadUrl || item.fileUrl |
| | | if (!fileUrl) return |
| | | |
| | | const fullUrl = formatUrl(fileUrl) |
| | | |
| | | if (item.contentType?.startsWith('image/')) { |
| | | images.push(item.url) |
| | | images.push(fullUrl) |
| | | } else if (item.contentType?.startsWith('video/')) { |
| | | videos.push(item.url) |
| | | videos.push(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-preview { |
| | | .video-thumbnail { |
| | | width: 100%; |
| | | height: 100%; |
| | | background-color: #333; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | position: relative; |
| | | display: block; |
| | | } |
| | | |
| | | .video-tip { |
| | | .hidden-video { |
| | | position: absolute; |
| | | bottom: 5px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | font-size: 12px; |
| | | color: #fff; |
| | | background-color: rgba(0, 0, 0, 0.6); |
| | | padding: 2px 8px; |
| | | border-radius: 4px; |
| | | top: -9999px; |
| | | left: -9999px; |
| | | width: 1px; |
| | | height: 1px; |
| | | opacity: 0; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .empty-state { |