From 1d552a3bad95caae4af15322df28e6240b797693 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Thu, 13 Aug 2026 15:32:06 +0800
Subject: [PATCH] feat: app视频封面图
---
applications/mobile-web-view/src/appPages/work/workDetail/index.vue | 246 ++++++++++++++++++++++++++++++++++--------------
1 files changed, 172 insertions(+), 74 deletions(-)
diff --git a/applications/mobile-web-view/src/appPages/work/workDetail/index.vue b/applications/mobile-web-view/src/appPages/work/workDetail/index.vue
index 90aada8..10e7443 100644
--- a/applications/mobile-web-view/src/appPages/work/workDetail/index.vue
+++ b/applications/mobile-web-view/src/appPages/work/workDetail/index.vue
@@ -2,125 +2,225 @@
<div class="workDetailContainer">
<div class="detailTop">
<div class="image-container">
- <van-swipe class="detailSwipe" :autoplay="3000" indicator-color="#4C85FF">
- <van-swipe-item v-for="(img, index) in getImageList" :key="index">
- <van-image class="detailImage" :src="img" fit="cover" width="100%" height="200px"
- @click="openPreview(index)" preview-visible="false" />
+ <video
+ v-if="isVideoAttachment && mediaSrc"
+ ref="videoRef"
+ class="video-js vjs-default-skin vjs-big-play-centered detailVideo"
+ controls
+ preload="auto"
+ playsinline
+ ></video>
+ <van-swipe v-else :autoplay="3000" indicator-color="#4C85FF">
+ <van-swipe-item v-for="(img, index) in [mediaSrc]" :key="index">
+ <van-image
+ class="detailImage"
+ :src="img"
+ fit="cover"
+ width="100%"
+ height="235px"
+ @click="openPreview(index)"
+ preview-visible="false"
+ />
</van-swipe-item>
</van-swipe>
-
- <van-image-preview v-model:show="previewShow" :images="getImageList" :initial-index="previewIndex" />
</div>
</div>
- <!-- 工单内容 -->
- <div class="worderContainer">
- <div class="workOrderContent">
- <div class="workOrderTitle">工单内容</div>
- <div class="workOrderContainer">
- <div class="orderRow">
- <div class="rowTitle">工单编号</div>
- <div>{{ workDetailData.eventNum }}</div>
- </div>
- <div class="orderRow">
- <div class="rowTitle">工单处置人</div>
- <div>{{ workDetailData.disposeUserName }}</div>
- </div>
- <div class="orderRow">
- <div class="rowTitle">处置部门</div>
- <div>{{ workDetailData.disposeDeptName }}</div>
- </div>
- <div class="orderRow">
- <div class="rowTitle">拍摄时间</div>
- <div>{{ workDetailData.shootTime }}</div>
- </div>
- <div class="orderRow">
- <div class="rowTitle">分发人员</div>
- <div>{{ workDetailData.distributeUserName }}</div>
- </div>
- <div class="orderRow">
- <div class="rowTitle">分发部门</div>
- <div>{{ workDetailData.distributeDeptName }}</div>
- </div>
+ <!-- 工单内容 -->
+ <div class="worderContainer">
+ <div class="workOrderContent">
+ <div class="workOrderTitle">工单内容</div>
+ <div class="workOrderContainer">
+ <div class="orderRow">
+ <div class="rowTitle">工单名称</div>
+ <div>{{ workDetailData.eventName }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">工单编号</div>
+ <div>{{ workDetailData.eventNum }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">工单处置人</div>
+ <div>{{ workDetailData.disposeUserName }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">处置部门</div>
+ <div>{{ workDetailData.disposeDeptName }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">拍摄时间</div>
+ <div>{{ workDetailData.shootTime }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">分发人员</div>
+ <div>{{ workDetailData.distributeUserName }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">分发部门</div>
+ <div>{{ workDetailData.distributeDeptName }}</div>
+ </div>
- <div class="orderRow">
- <div class="rowTitle">分发时间</div>
- <div>{{ workDetailData.distributeTime }}</div>
- </div>
- <div class="orderRow">
- <div class="rowTitle">工单位置</div>
- <div class="rowAddress" @click="jumpMap(workDetailData)">{{ workDetailData.eventLocation }}</div>
- </div>
- </div>
- </div>
- </div>
+ <div class="orderRow">
+ <div class="rowTitle">分发时间</div>
+ <div>{{ workDetailData.distributeTime }}</div>
+ </div>
+ <div class="orderRow">
+ <div class="rowTitle">工单位置</div>
+ <div class="rowAddress" @click="jumpMap(workDetailData)">{{ workDetailData.eventLocation }}</div>
+ </div>
+ </div>
+ </div>
+ </div>
</div>
</template>
<script setup>
+import { getSharingDetailsApi } from '@/api/work/index'
import { showToast, showNotify, showImagePreview } from 'vant'
-import { getShowImg, getSmallImg } from '@/utils/util'
-import { useRoute } from 'vue-router'
-
+import { useRoute, useRouter } from 'vue-router'
+import { drawAiFrame, replaceWithProxy } from '@ztzf/utils'
+import videojs from 'video.js'
+import 'video.js/dist/video-js.css'
+const keyword = ref('')
const route = useRoute()
+const router = useRouter()
const workDetailData = ref({})
+const videoRef = ref(null)
+let player = null
+
+const isVideoAttachment = computed(() => Number(workDetailData.value.attachmentType) === 3)
// 预览图片
-const previewShow = ref(false)
-const previewIndex = ref(0)
const getImageList = computed(() => {
const imageArr = []
const detail = workDetailData.value
if (detail.eventImageUrl) {
- const smallUrl = getSmallImg(detail.eventImageUrl)
+ const smallUrl = detail.eventImageUrl
imageArr.push(smallUrl)
}
return imageArr
})
-const openPreview = index => {
- const detail = workDetailData.value
- const showUrl = getShowImg(detail.eventImageUrl)
+const openPreview = () => {
+ if (isVideoAttachment.value || !mediaSrc.value) return
showImagePreview({
- images: [showUrl],
+ images: [mediaSrc.value],
startPosition: 0,
})
- previewIndex.value = index
- previewShow.value = true
}
// 跳转地图
const jumpMap = item => {
- const transmitData = { data: { type: 'jumpMapNav', eventNum: item.event_num } }
- wx.miniProgram.navigateTo({ url: `/subPackages/workDetail/mapWork/index?currentItem=${item.event_num}` })
- wx.miniProgram.postMessage(transmitData)
- uni.postMessage(transmitData)
+ router.push({
+ path: '/webViewWrapper/mapWork',
+ query: {
+ currentItem: JSON.stringify(item),
+ },
+ })
}
-onMounted(async () => {
-workDetailData.value = JSON.parse(route.query.workDetailData)
-console.log('route.query',workDetailData.value);
+function getVideoType(url) {
+ const path = (url || '').split('?')[0].toLowerCase()
+ if (path.endsWith('.m3u8')) return 'application/x-mpegURL'
+ if (path.endsWith('.mp4')) return 'video/mp4'
+ if (path.endsWith('.webm')) return 'video/webm'
+ if (path.endsWith('.ogg') || path.endsWith('.ogv')) return 'video/ogg'
+ if (path.endsWith('.mov')) return 'video/quicktime'
+ return ''
+}
+
+function getVideoSource() {
+ const type = getVideoType(mediaSrc.value)
+ return {
+ src: mediaSrc.value,
+ ...(type ? { type } : {}),
+ }
+}
+
+function destroyPlayer() {
+ if (!player) return
+ player.dispose()
+ player = null
+}
+
+async function initPlayer() {
+ if (!isVideoAttachment.value || !mediaSrc.value) return
+ await nextTick()
+ if (!videoRef.value) return
+
+ if (player) {
+ player.src(getVideoSource())
+ player.load()
+ return
+ }
+
+ player = videojs(videoRef.value, {
+ controls: true,
+ preload: 'auto',
+ autoplay: false,
+ fluid: false,
+ sources: [getVideoSource()],
+ })
+ player.on('error', () => {
+ console.error('视频播放失败:', player?.error(), mediaSrc.value)
+ })
+}
+
+const mediaSrc = ref('')
+
+watch([isVideoAttachment, mediaSrc], () => {
+ if (isVideoAttachment.value) {
+ initPlayer()
+ } else {
+ destroyPlayer()
+ }
})
+
+onMounted(async () => {
+ keyword.value = JSON.parse(route.query.workDetailData)
+ try {
+ const res = await getSharingDetailsApi({ cacheKey: keyword.value })
+ workDetailData.value = res.data.data
+ let { eventImageUrl, geojson } = workDetailData.value
+ // http://220.177.172.27:8100 改为 https://wrj.shuixiongit.com/ja-proxy
+ eventImageUrl = replaceWithProxy(eventImageUrl)
+ if (eventImageUrl) {
+ mediaSrc.value = !isVideoAttachment.value && geojson ? await drawAiFrame(eventImageUrl, geojson) : eventImageUrl
+ }
+ } catch (error) {
+ showToast('分享链接失效')
+ }
+})
+
+onBeforeUnmount(destroyPlayer)
</script>
<style lang="scss" scoped>
.workDetailContainer {
- padding-top: 44px;
.detailTop {
.image-container {
position: relative;
width: 100%;
- height: 205px;
-
+ height: 235px;
.detailImage {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
+
+ .detailVideo {
+ width: 100%;
+ height: 235px;
+ }
+
+ :deep(.video-js .vjs-tech) {
+ width: 100%;
+ height: 100%;
+ }
}
}
.worderContainer {
padding: 0 12px;
- padding-bottom: 2px;
+ // padding-bottom: 2px;
background: #f6f6f6;
}
@@ -128,7 +228,7 @@
margin-top: 15px;
background-color: #fff;
border-radius: 6px;
- padding: 10px;
+ padding: 8px 10px;
margin-bottom: 17px;
.workOrderTitle {
@@ -182,8 +282,8 @@
}
.rowAddress {
- font-family: Source Han Sans CN, Source Han Sans CN;
- font-weight: 400;
+ font-family: Source Han Sans CN, Source Han Sans CN;
+ font-weight: 400;
font-size: 14px;
color: #1d6fe9;
text-decoration: underline;
@@ -200,9 +300,7 @@
:deep(.custom-field .van-field__control) {
padding: 0 !important;
}
-
}
}
-
}
</style>
--
Gitblit v1.9.3