mrr.sj.front/components/dynamic-form/FormItemVideo.vue

257 lines
6.6 KiB
Vue
Raw Normal View History

2026-06-09 17:49:15 +08:00
<template>
2026-06-10 16:23:47 +08:00
<view>
2026-06-11 20:48:30 +08:00
<view v-if="maxCount > 1" class="video-list">
<view v-for="(item, index) in currentList" :key="index" class="video-wrapper">
2026-06-12 13:59:52 +08:00
<image :src="getVideoPoster(item)" class="preview-video" mode="aspectFill" @click="previewVideo(item)" />
<view class="play-mask" @click="previewVideo(item)">
<view class="play-circle">
<view class="play-icon"></view>
</view>
2026-06-11 20:48:30 +08:00
</view>
2026-06-12 13:59:52 +08:00
<image
class="delete-btn"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/6ab3fc63-3bad-403d-bbfc-9609a93c048a.png"
mode="aspectFit"
@click="deleteVideo(index)"
></image>
2026-06-11 20:48:30 +08:00
</view>
2026-06-12 13:59:52 +08:00
<ali-oss-uploader v-if="currentList.length < maxCount"
2026-06-11 20:48:30 +08:00
:max-count="maxCount - currentList.length"
:max-size="maxSize" accept="video/*" :userId="uploadUserId" :type="ossType" :kind="2" width="200rpx"
2026-06-12 13:59:52 +08:00
:show-preview="false"
2026-06-11 20:48:30 +08:00
@input="onMultiInput" @change="onChange" />
</view>
<view v-else>
<ali-oss-uploader v-if="!currentValue" :max-count="1" :max-size="maxSize" accept="video/*"
:userId="uploadUserId" :type="ossType" :kind="2" width="100%" :file-string="currentValue" @input="onInput"
@change="onChange" @success="onInput" @delete="deleteSingleVideo" />
<view v-else class="video-wrapper">
2026-06-12 13:59:52 +08:00
<image :src="getVideoPoster(currentValue)" class="preview-video" mode="aspectFill" @click="previewVideo(currentValue)" />
<view class="play-mask" @click="previewVideo(currentValue)">
<view class="play-circle">
<view class="play-icon"></view>
</view>
</view>
<image
class="delete-btn"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/6ab3fc63-3bad-403d-bbfc-9609a93c048a.png"
mode="aspectFit"
@click="deleteSingleVideo"
></image>
</view>
</view>
<view v-if="showPlayer" class="player-mask" @click="closePlayer">
<view class="player-box" @click.stop>
<video :src="playingVideo" class="player-video" controls autoplay show-fullscreen-btn />
<view class="player-close" @click="closePlayer">
<text class="player-close-text">&times;</text>
2026-06-11 20:48:30 +08:00
</view>
2026-06-09 17:49:15 +08:00
</view>
</view>
</view>
</template>
<script>
2026-06-10 16:23:47 +08:00
import AliOssUploader from '../ali-oss-uploader/ali-oss-uploader.vue'
2026-06-09 17:49:15 +08:00
export default {
2026-06-10 10:15:10 +08:00
name: 'FormItemVideo',
2026-06-10 16:23:47 +08:00
components: { AliOssUploader },
2026-06-09 17:49:15 +08:00
props: {
2026-06-11 20:48:30 +08:00
value: { type: [String, Array], default: '' },
maxSize: { type: Number, default: 100 },
maxCount: { type: Number, default: 1 },
userId: { type: [Number, String], default: null }
2026-06-09 17:49:15 +08:00
},
2026-06-10 10:15:10 +08:00
data: function () {
2026-06-09 17:49:15 +08:00
return {
2026-06-11 20:48:30 +08:00
currentValue: '',
2026-06-12 13:59:52 +08:00
currentList: [],
showPlayer: false,
playingVideo: ''
2026-06-09 17:49:15 +08:00
};
},
2026-06-10 16:23:47 +08:00
computed: {
2026-06-11 20:48:30 +08:00
uploadUserId: function () {
if (this.userId) return this.userId;
2026-06-10 16:23:47 +08:00
return this.$store && this.$store.state && this.$store.state.sjInfo
? this.$store.state.sjInfo.id : null;
},
ossType: function () {
var artisanType = getApp().globalData ? getApp().globalData.artisanType : 0;
return (artisanType || 0) + 1;
}
},
2026-06-09 17:49:15 +08:00
watch: {
value: {
2026-06-10 10:15:10 +08:00
handler: function (val) {
2026-06-11 20:48:30 +08:00
if (this.maxCount > 1) {
if (Array.isArray(val)) {
this.currentList = val.filter(function (v) { return !!v; });
} else if (val) {
this.currentList = [val];
} else {
this.currentList = [];
}
} else {
this.currentValue = Array.isArray(val) ? (val[0] || '') : (val || '');
}
2026-06-09 17:49:15 +08:00
},
immediate: true
}
},
methods: {
2026-06-10 16:23:47 +08:00
onInput: function (val) {
this.currentValue = val;
this.$emit('input', val);
},
2026-06-11 20:48:30 +08:00
onMultiInput: function (val) {
var arr = Array.isArray(val) ? val : [val];
2026-06-12 13:59:52 +08:00
var existing = this.currentList.filter(function (item) {
return arr.indexOf(item) === -1;
});
var list = existing.concat(arr).filter(function (item, index, self) {
return item && self.indexOf(item) === index;
}).slice(0, this.maxCount);
2026-06-11 20:48:30 +08:00
this.currentList = list;
this.$emit('input', list);
},
2026-06-10 16:23:47 +08:00
onChange: function (val) {
this.$emit('change', val);
2026-06-09 17:49:15 +08:00
},
2026-06-12 13:59:52 +08:00
getVideoPoster: function (url) {
if (!url) return '';
if (String(url).indexOf('x-oss-process=') > -1) return url;
var connector = String(url).indexOf('?') > -1 ? '&' : '?';
return url + connector + 'x-oss-process=video/snapshot,t_2000,f_jpg,m_fast';
},
previewVideo: function (url) {
if (!url) return;
this.playingVideo = url;
this.showPlayer = true;
},
closePlayer: function () {
this.showPlayer = false;
this.playingVideo = '';
},
2026-06-11 20:48:30 +08:00
deleteSingleVideo: function () {
2026-06-10 16:23:47 +08:00
this.currentValue = '';
2026-06-10 10:15:10 +08:00
this.$emit('input', '');
2026-06-11 20:48:30 +08:00
},
deleteVideo: function (index) {
this.currentList.splice(index, 1);
this.$emit('input', this.currentList);
2026-06-09 17:49:15 +08:00
}
}
};
</script>
<style scoped>
2026-06-11 20:48:30 +08:00
.video-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
2026-06-10 16:23:47 +08:00
.video-wrapper {
position: relative;
2026-06-10 10:15:10 +08:00
width: 200rpx;
height: 200rpx;
2026-06-12 13:59:52 +08:00
overflow: visible;
2026-06-09 17:49:15 +08:00
}
2026-06-10 10:15:10 +08:00
.preview-video {
width: 200rpx;
height: 200rpx;
2026-06-09 17:49:15 +08:00
border-radius: 8rpx;
2026-06-12 13:59:52 +08:00
background-color: #f5f5f5;
}
.play-mask {
position: absolute;
left: 0;
top: 0;
width: 200rpx;
height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.15);
border-radius: 8rpx;
z-index: 2;
}
.play-circle {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.55);
display: flex;
align-items: center;
justify-content: center;
}
.play-icon {
width: 0;
height: 0;
border-top: 14rpx solid transparent;
border-bottom: 14rpx solid transparent;
border-left: 22rpx solid #ffffff;
margin-left: 6rpx;
2026-06-09 17:49:15 +08:00
}
2026-06-10 10:15:10 +08:00
2026-06-09 17:49:15 +08:00
.delete-btn {
position: absolute;
2026-06-10 16:23:47 +08:00
top: -10rpx;
right: -10rpx;
2026-06-12 13:59:52 +08:00
width: 42rpx;
height: 42rpx;
z-index: 5;
}
.player-mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.82);
z-index: 9999;
2026-06-09 17:49:15 +08:00
display: flex;
2026-06-12 13:59:52 +08:00
align-items: center;
2026-06-09 17:49:15 +08:00
justify-content: center;
2026-06-12 13:59:52 +08:00
padding: 32rpx;
box-sizing: border-box;
}
.player-box {
position: relative;
width: 100%;
}
.player-video {
width: 100%;
height: 420rpx;
background-color: #000000;
}
.player-close {
position: absolute;
right: -12rpx;
top: -58rpx;
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.22);
display: flex;
2026-06-10 16:23:47 +08:00
align-items: center;
2026-06-12 13:59:52 +08:00
justify-content: center;
2026-06-09 17:49:15 +08:00
}
2026-06-10 10:15:10 +08:00
2026-06-12 13:59:52 +08:00
.player-close-text {
2026-06-09 17:49:15 +08:00
color: #ffffff;
2026-06-12 13:59:52 +08:00
font-size: 42rpx;
line-height: 48rpx;
2026-06-09 17:49:15 +08:00
}
</style>