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