<template>
<div class="rightInfo">
<van-image-preview v-model:show="show" :startPosition="startPosition" :images="picUrl" @change="onChange" />
<van-overlay v-model:show="showDialog" @click="showDialog = false" :lock-scroll="false">
<div class="block">
<div class="content">
<div ref="traceTitle">
<p class="traceTitle">1111111</p>
</div>
<div class="content-track">
<logistics-track :data-source="trackList"></logistics-track>
</div>
<div class="opacity"></div>
</div>
<div class="cancel" @click="showDialog = false">我知道了</div>
</div>
</van-overlay>
<div v-if="dataList" class="info">
<div class="timeBar">
<div class="time">{{ dataList.createTime }}</div>
<div class="nickname">{{ type ? dataList.registrationNetworkName : dataList.replyNetworkName }}</div>
</div>
<!-- 详情部分 -->
<div v-if="type" class="mainInfo">
<div class="infoLine">
<span class="infoTitle">详情</span>
<span class="trace" @click="openTrack">111111</span>
</div>
<div class="infoLine">
<span class="infoName">单号: </span>
<span class="infoValue">{{ dataList.waybillNo }}</span>
</div>
<div class="infoLine">
<span class="infoName">2222: </span>
<span class="infoValue">{{ dataList.receiveNetworkName }}</span>
<span></span>
</div>
<div class="infoLine">
<span class="infoName">类型1: </span>
<span class="infoValue">{{ dataList.probleTypeSubjectName }}</span>
<span></span>
</div>
<div class="infoLine">
<span class="infoName">类型2: </span>
<span class="infoValue">{{ dataList.secondLevelTypeName }}</span>
<span></span>
</div>
<div class="infoLine">
<span class="infoName">问题件状态: </span>
<span class="infoValue">{{ dataList.problePieceStatus === 1 ? '待处理' : dataList.problePieceStatus === 2 ? '处理中'
: '已处理'
}}</span>
<span></span>
</div>
<div v-if="dataList.urls && dataList.urls.length" class="infoLineImg">
<div class="infoName">图片: </div>
<van-swipe class="extra" indicator-color="white">
<van-swipe-item class="extra-swiper" v-for="(imgItem, imgIndex) in dataList.urls" :key="imgIndex">
<img :src="imgItem" @click="reviewPic(dataList.urls, imgIndex)">
</van-swipe-item>
<!-- swiper指示器 -->
<template #indicator="{ active, total }">
<div class="extra-indicator">{{ active + 1 }}/{{ total }}</div>
</template>
</van-swipe>
</div>
<div v-if="dataList.videoList && dataList.videoList.length" class="infoLineImg infoLineVideo">
<div class="infoName">视频: </div>
<van-swipe class="extra" id="extra" @change="swiperChange">
<van-swipe-item class="extra-swiper" v-for="(videoItem, videoIndex) in dataList.videoList"
:key="videoIndex">
<video :id="'video' + videoIndex" crossOrigin="anonymous"
:src="videoItem.url" :controls="showControls" style="object-fit:cover;">
</video>
<!-- 添加遮罩 避免video滑动无法触发轮播 -->
<div v-if="!showControls" class="play" @click="playSwiperVideo(videoIndex)">
<img class="btn" src="@/assets/img/play.png" @click="clickPlayVideo(videoItem.url)" />
</div>
</van-swipe-item>
<!-- 自定义swiper指示器 -->
<template #indicator="{ active, total }">
<div class="extra-indicator">{{ active + 1 }}/{{ total }}</div>
</template>
</van-swipe>
</div>
</div>
<!-- 内容部分 -->
<div v-else class="mainInfo">
<div class="infoLine">
<div class="infoValue">{{ dataList.replyContent }}</div>
</div>
<div class="infoLine" v-if="dataList.urls && dataList.urls.length">
<div class="infoLineImg">
<van-swipe class="extra" indicator-color="white">
<van-swipe-item class="extra-swiper" v-for="(imgItem, imgIndex) in dataList.urls" :key="imgIndex">
<img :src="imgItem" @click="reviewPic(dataList.urls, imgIndex)">
</van-swipe-item>
<!-- swiper指示器 -->
<template #indicator="{ active, total }">
<div class="extra-indicator">{{ active + 1 }}/{{ total }}</div>
</template>
</van-swipe>
</div>
</div>
</div>
</div>
<div class="avatar">
<img src="@/assets/img/default.png">
</div>
</div>
</template>
<script lang="ts">
import { CommonResModel } from '@/api/model/commonModel'
import { getOrderTrackDetailRes, getOrderTrackRes } from '@/api/model/workOrderManageModel'
import { playVideo } from '@/utils/nativeAPI'
import AjaxWorkOrderManageService from '@/api/workOrderManage'
import { defineComponent, ref } from 'vue'
import LogisticsTrack from "@/components/LogisticsTrack/src/LogisticsTrack.vue"
export default defineComponent({
components: { LogisticsTrack },
props: {
dataList: {
default: () => {
return {}
},
type: Object,
},
type: {
type: Boolean,
default: false
}
},
setup(props) {
const { dataList } = props
// 判断是否是视频
const showDialog = ref<boolean>(false)
// 查看物流轨迹
const trackList = ref<getOrderTrackDetailRes[]>([])
function openTrack() {
AjaxWorkOrderManageService.getOrderTrack({
waybillNos: dataList.waybillNo
})
.then((res: CommonResModel<getOrderTrackRes[]>) => {
if (res.code === 1) {
trackList.value = res.data ? res.data[0].details : []
showDialog.value = true
// const trackNetworkIds: any = []
// trackList.value.map(c => {
// trackNetworkIds.push(c.scanNetworkId)
// })
}
})
.catch((err) => {
})
}
const index = ref<number>(0)
const show = ref<boolean>(false)
const picUrl = ref<Array<string>>([''])
const startPosition = ref<number>(0)
const reviewPic = (value: string[], num: number) => {
show.value = true
picUrl.value = value
startPosition.value = num
}
const onChange = (newIndex) => {
index.value = newIndex
}
const showControls = ref<boolean>(false)
function playSwiperVideo(e) {
const videoRef: any = document.getElementById(`video${e}`)
videoRef.play()
showControls.value = true
// 视频暂停,显示遮罩
videoRef.addEventListener("pause", () => {
showControls.value = false
})
}
// swiper切换,中止视频播放
function swiperChange() {
if (dataList.videoList && dataList.videoList.length) {
for (let index = 0; index < dataList.videoList.length; index++) {
const element = dataList.videoList[index];
getVideoBase64(element.url, index)
const videoRef: any = document.getElementById(`video${index}`)
videoRef.pause()
}
}
}
let dataURL = '';
const getVideoBase64 = (url, videoIndex) => {
// console.log(url, "1111111111111")
return new Promise(function (resolve) {
const video = document.createElement('video');
video.setAttribute('crossOrigin', 'anonymous'); // 处理跨域
video.setAttribute('src', url);
video.setAttribute('preload', 'auto');
video.addEventListener('loadeddata', function () {
const canvas = document.createElement('canvas');
const width = video.videoWidth || 115; // canvas的尺寸和图片一样
const height = video.videoHeight || 114;// 设置默认宽高为 400 240
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(video, 0, 0, width, height); // 绘制canvas
dataURL = canvas.toDataURL('image/jpeg'); // 转换为base64
// document.getElementById('video' + videoIndex).setAttribute('poster', dataURL)
document.getElementById('extra').style.background =`url(${dataURL})`;
document.getElementById('extra').style.backgroundSize ='cover';
document.getElementById('extra').style.backgroundPosition ="center center";
console.log(document.getElementById('extra').style.background, "222222222")
resolve(dataURL);
});
});
}
if (dataList.videoList && dataList.videoList.length) {
getVideoBase64(dataList.videoList[0].url, 0)
}
const clickPlayVideo = (videoPath) => {
console.log(videoPath, "原生播放传递路径")
if (videoPath) {
playVideo(videoPath)
}
}
return {
index,
showDialog,
show,
picUrl,
onChange,
trackList,
openTrack,
reviewPic,
startPosition,
playSwiperVideo,
showControls,
dataURL,
swiperChange,
getVideoBase64,
clickPlayVideo,
playVideo,
}
}
})
</script>
<style scoped lang="scss">
.rightInfo {
display: flex;
flex-direction: row;
margin: 19px 0 19px 10px;
border-radius: 10px;
padding: 10px 12px;
justify-content: flex-end;
.avatar>img {
width: 38px;
height: 38px;
border-radius: 50%;
}
.info {
margin-right: 8px;
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
.timeBar {
display: flex;
flex-direction: row;
justify-content: flex-end;
width: 100%;
.nickname {
font-weight: bold;
color: #3C3C3C;
font-size: $font12;
}
.time {
margin: 0 8px 8px 0;
color: #999999;
font-size: $font12;
}
}
.mainInfo {
max-width: 244px;
display: flex;
background: #ffffff;
border-radius: 10px;
font-size: $font12;
padding: 10px 12px;
width: auto;
flex-direction: column;
.infoLine {
margin: 5px 0;
.infoName {
color: #7A7A7A;
}
.infoValue {
color: #3C3C3C;
font-weight: bold;
margin-left: 5px;
text-align: end;
line-break: anywhere;
text-align: left;
}
.infoLineImg {
color: #7A7A7A;
display: flex;
justify-content: flex-end;
.extra {
max-width: 140px;
height: 105px;
border-radius: 8px;
margin-left: 5px;
border: 1px solid #b7b7b74d;
position: relative;
&-swiper {
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
}
video {
width: 100%;
height: 100%;
z-index: -100;
}
.play {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
.btn {
width: 30px;
height: 30px;
}
}
}
&-indicator {
position: absolute;
top: 2px;
right: 2px;
background-color: #7a7a7a;
padding: 0 4px;
height: 20px;
line-height: 20px;
color: #ffffff;
border-radius: 8px;
}
}
.imgNum {
width: 23px;
height: 20px;
background: #7a7a7a;
border-radius: 8px;
color: #ffffff;
position: relative;
text-align: center;
top: 5px;
left: 140px;
line-height: 20px;
}
}
.infoTitle {
font-weight: bold;
font-size: $font14;
color: #3C3C3C;
}
.trace {
font-size: $font12;
font-weight: bold;
color: #e6262c;
margin-left: 14px;
}
}
.infoLineImg {
color: #3C3C3C;
display: flex;
justify-content: flex-start;
.extra {
width: 140px;
height: 105px;
border-radius: 8px;
margin-left: 5px;
border: 1px solid #b7b7b74d;
&-swiper {
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
}
video {
width: 100%;
height: 100%;
z-index: -100;
}
.play {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
.btn {
width: 30px;
height: 30px;
}
}
}
&-indicator {
position: absolute;
top: 2px;
right: 2px;
background-color: #7a7a7a;
padding: 0 4px;
height: 20px;
line-height: 20px;
color: #ffffff;
border-radius: 8px;
}
}
.imgNum {
width: 23px;
height: 20px;
background: #7a7a7a;
border-radius: 8px;
color: #ffffff;
position: relative;
text-align: center;
top: 5px;
right: 30px;
line-height: 20px;
}
.infoName {
color: #7A7A7A;
}
}
}
}
:deep(.van-overlay) {
.block {
width: calc(100% - 84px);
max-height: 487px;
height: 487px;
top: 50%;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background: #ffffff;
border-radius: 6px;
.content {
height: 480px;
.traceTitle {
font-size: $font18;
font-weight: bold;
text-align: center;
color: #3c3c3c;
padding: 19px;
}
.opacity {
width: 100%;
height: 42px;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.00), #ffffff 87%);
position: relative;
bottom: 30px;
}
.detail {
height: 410px !important;
overflow: auto;
}
&-track {
height: 400px;
overflow: auto;
}
}
.cancel {
text-align: center;
height: 48px;
line-height: 48px;
background: #ffffff;
font-size: $font16;
font-weight: bold;
border-top: 1px solid #f0f0f0;
border-radius: 0 0 6px 6px;
}
}
}
}
</style>
vue3 上传视频 第一帧放在背景色上
于 2022-08-16 14:46:26 首次发布