图片、视频加载方式

This commit is contained in:
zhujingzhou
2025-07-20 11:36:46 +07:00
parent 2ab6513b73
commit fa06b597e5
17 changed files with 1204 additions and 375 deletions
+1 -1
View File
@@ -18,7 +18,7 @@
}, },
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "lint-staged"
} }
}, },
"lint-staged": { "lint-staged": {
+19 -1
View File
@@ -1,3 +1,9 @@
<!--
* @Date: 2024-05-21 21:33:04
* @LastEditors: Administrator admin@example.com
* @LastEditTime: 2024-06-17 17:59:57
* @FilePath: /txsm_webAdmin/src/App.vue
-->
<template> <template>
<div id="app"> <div id="app">
<router-view /> <router-view />
@@ -5,17 +11,29 @@
</template> </template>
<script> <script>
import mixinSyscfg from './mixins/mixinSyscfg'
export default { export default {
name: 'App' name: 'App',
mixins: [mixinSyscfg],
async created() {
await this.getSyscfg()
}
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.el-tooltip__popper { .el-tooltip__popper {
max-width: 600px; max-width: 600px;
} }
.el-table { .el-table {
font-size: 12px !important; font-size: 12px !important;
color: rgb(56, 51, 51) !important; color: rgb(56, 51, 51) !important;
} }
.tag-wrap {
// height: 200px;
overflow: scroll;
overflow-x: hidden;
}
</style> </style>
+60 -17
View File
@@ -8,13 +8,17 @@
--> -->
<template> <template>
<div> <div>
<quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" @ready="onEditorReady($event)"></quill-editor> <quill-editor
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@ready="onEditorReady($event)"></quill-editor>
<!-- el-uploader不好手动触发上传功能 --> <!-- el-uploader不好手动触发上传功能 -->
<uploader <uploader
:style="{ display: 'none' }" :style="{ display: 'none' }"
:options="{ ...options, target: '/api/web/file/uploadImg' }" :options="{ ...options, target: '/api/web/file/uploadImg' }"
class="uploader-example" class="uploader-example"
@file-success="imageSuccess"> @file-success="imageSuccess">
<uploader-drop> <uploader-drop>
<uploader-btn ref="editorUploadImg" :attrs="attrsImg"></uploader-btn> <uploader-btn ref="editorUploadImg" :attrs="attrsImg"></uploader-btn>
</uploader-drop> </uploader-drop>
@@ -22,6 +26,7 @@
</div> </div>
</template> </template>
<script> <script>
import { handleVerAutoImg } from '@/utils/index.js'
import 'quill/dist/quill.core.css' import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css' import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css' import 'quill/dist/quill.bubble.css'
@@ -31,6 +36,7 @@ Link.PROTOCOL_WHITELIST = ['http', 'https', 'mailto', 'tel', 'yinseinner']
import { quillEditor } from 'vue-quill-editor' import { quillEditor } from 'vue-quill-editor'
import { ImageDrop } from 'quill-image-drop-module' import { ImageDrop } from 'quill-image-drop-module'
import ImageResize from 'quill-image-resize-module' import ImageResize from 'quill-image-resize-module'
import { data } from 'qrcode.vue'
Quill.register('modules/imageDrop', ImageDrop) Quill.register('modules/imageDrop', ImageDrop)
Quill.register('modules/imageResize', ImageResize) Quill.register('modules/imageResize', ImageResize)
@@ -49,6 +55,7 @@ export default {
textNode: { textNode: {
default: '' default: ''
} }
}, },
computed: { computed: {
options() { options() {
@@ -69,7 +76,8 @@ export default {
const _that = this const _that = this
return { return {
content: '', content: '',
domain: this.$store.getters.getSystemConfig.webImgReq, imgPath: [],
domain: this.$store.getters.getSystemConfig.webImgReq, // 不能暴露源站地址
attrsImg: { attrsImg: {
accept: ['image/*'] accept: ['image/*']
}, },
@@ -105,7 +113,7 @@ export default {
} }
}, },
// //配置富文本框图片大小调整功能 // //配置富文本框图片大小调整功能
// imageDrop: true, imageDrop: true,
imageResize: { imageResize: {
displayStyles: { displayStyles: {
backgroundColor: 'black', backgroundColor: 'black',
@@ -114,6 +122,7 @@ export default {
}, },
modules: ['Resize', 'DisplaySize', 'Toolbar'] modules: ['Resize', 'DisplaySize', 'Toolbar']
} }
} }
} }
@@ -121,33 +130,67 @@ export default {
} }
}, },
mounted() {},
methods: { methods: {
// 父组件获取数据 // 父组件获取数据
getdata() { getdata() {
const str = this.content.replace(this.domain, '') // 获取 Quill 编辑器中的所有 img 标签
const imgElements = this.$refs.myQuillEditor.quill.container.querySelectorAll('img')
// 存储自定义属性值
const customAttrValues = []
// 遍历所有 img 标签并获取自定义属性值
imgElements.forEach(img => {
const customAttrValue = img.getAttribute('data-custom') // 假设自定义属性是 data-custom
if (customAttrValue) {
customAttrValues.push(customAttrValue) // 添加到数组中
}
})
// 替换 img 标签的 src
for (let i = 0; i < imgElements.length; i++) {
const newSrc = customAttrValues[i]
const regex = new RegExp(`<img\\s+([^>]*?)src="([^"]*)"([^>]*?)>`, 'i')
return str this.content = this.content.replace(regex, (match, beforeSrc, oldSrc, afterSrc) => {
// 使用 oldSrc 设置 data-custom 属性,同时替换 src
return `<img ${beforeSrc} src="${newSrc}" data-custom="${oldSrc}"${afterSrc}>`
})
}
return this.content
}, },
// 当文本框加载完成时,编译插入数据 // 当文本框加载完成时,编译插入数据
async onEditorReady(e) { async onEditorReady(e) {
const data = this.textNode.replace('img src="', 'img src="' + this.domain) this.content = this.textNode.replace(/<img\s+([^>]*?)src="([^"]*?)"[^>]*data-custom="([^"]*?)"([^>]*?)>/g, (match, before, srcValue, customValue, after) => {
e.container.querySelector('.ql-blank').innerHTML = data // 互换 src 和 data-custom 的值
return `<img ${before}src="${customValue}" data-custom="${srcValue}"${after}>`
})
}, },
imageSuccess(rootFile, file, message) { async imageSuccess(rootFile, file, message) {
const { code, data } = JSON.parse(message) const { code, data } = JSON.parse(message)
if (code === 200) { if (code === 200) {
this.storageBase64 = await handleVerAutoImg(this.domain + data.path)
const reader = new FileReader() const reader = new FileReader()
reader.readAsDataURL(file.file)
reader.onload = e => { reader.onload = async(e) => {
const base64Data = e.target.result // 获取转换后的 Data URL
const myeditor = this.$refs.myQuillEditor.quill const myeditor = this.$refs.myQuillEditor.quill
// editor方法获取当前光标位置 // 获取当前光标位置
const imgElement = document.createElement('img')
imgElement.src = base64Data
// 将 imgElement 插入到编辑器中
const index = myeditor.getSelection().index const index = myeditor.getSelection().index
myeditor.insertEmbed(index, 'image', this.domain + data.path) myeditor.insertEmbed(index, 'image', imgElement.src)
// 调整光标到图片之后的位置上 // 通过 Quill 的 API 将图片插入后,直接修改 DOM 来添加自定义属性
const imgNode = myeditor.container.querySelector(`img[src="${imgElement.src}"]`)
if (imgNode) {
imgNode.setAttribute('data-custom', data.path) // 设置自定义属性
}
myeditor.setSelection(index + 1) myeditor.setSelection(index + 1)
} }
// 读取 Blob 数据
reader.readAsDataURL(file.file)
} }
}, },
+12 -11
View File
@@ -6,10 +6,10 @@
* @LastEditTime: 2020-11-24 17:04:24 * @LastEditTime: 2020-11-24 17:04:24
--> -->
<template> <template>
<el-dialog append-to-body class="img_dialog" :title="title" align="center" :visible.sync="dialogVisible" width="40%" :before-close="handleClose" :close-on-click-modal="false" :modal-append-to-body='false'> <el-dialog class="img_dialog" append-to-body :title="title" align="center" :visible.sync="dialogVisible" width="40%" :before-close="handleClose" :close-on-click-modal="false" :modal-append-to-body='false'>
<el-carousel v-if="isArry" indicator-position="outside"> <el-carousel v-if="isArry" indicator-position="outside">
<el-carousel-item v-for="item in mediaUrl" :key="item"> <el-carousel-item v-for="item in mediaUrl" :key="item">
<div class="media-box" id="img-box" > <img :src="domain+item" /></div> <div class="media-box" id="img-box" > <img :src="changeImg(item)" /></div>
</el-carousel-item> </el-carousel-item>
</el-carousel> </el-carousel>
<div v-else class="media-box" id="img-box" > <img :src="mediaUrl" /></div> <div v-else class="media-box" id="img-box" > <img :src="mediaUrl" /></div>
@@ -17,6 +17,7 @@
</template> </template>
<script> <script>
import { handleVerAutoImg } from '@/utils/index.js'
export default { export default {
data() { data() {
return { return {
@@ -32,10 +33,14 @@ export default {
token() { token() {
return this.$store.state.token return this.$store.state.token
} }
}, },
mounted() { mounted() {
}, },
methods: { methods: {
async changeImg(url) {
return await handleVerAutoImg(this.domain + url)
},
handleClose() { handleClose() {
if (this.player) { if (this.player) {
this.player.dispose() this.player.dispose()
@@ -58,31 +63,26 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.my_data{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.img_dialog{ .img_dialog{
::v-deep{ ::v-deep{
.el-dialog__body{ .el-dialog__body{
height: auto; height: auto;
.el-carousel__item{ .el-carousel__item{
overflow: auto !important; overflow: auto !important;
} }
} }
} }
} }
.media-box { .media-box {
width: 100%; width: 100%;
height: 400px;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
img { img {
height: 100%; height: 100%;
max-width: 100%; width: 100%;
} }
#my-video { #my-video {
width: 100% !important; width: 100% !important;
@@ -90,4 +90,5 @@ export default {
border: none !important; border: none !important;
} }
} }
</style> </style>
+13 -15
View File
@@ -13,7 +13,7 @@
</div> </div>
<div class="showImg"> <div class="showImg">
<div v-if="showNoImg">暂无</div> <div v-if="showNoImg">暂无</div>
<el-image v-else :src="src" style="width: 100%, height: 100%" @click="checkMedia()" lazy > <el-image v-else :src="src" @click="checkMedia()" lazy >
<div slot="placeholder" class="image-slot" :style="{width: width, height: height, lineHeight: height}"> <div slot="placeholder" class="image-slot" :style="{width: width, height: height, lineHeight: height}">
<i class="el-icon-loading"></i>加载中 <i class="el-icon-loading"></i>加载中
</div> </div>
@@ -28,6 +28,7 @@
</template> </template>
<script> <script>
import Dialog from './components/dialog' import Dialog from './components/dialog'
import { handleVerAutoImg } from '@/utils/index.js'
export default { export default {
data() { data() {
return { return {
@@ -43,15 +44,12 @@ export default {
}, },
props: ['width', 'height', 'urls'], props: ['width', 'height', 'urls'],
watch: { watch: {
urls(newval, oldval) { async urls(newval, oldval) {
this.urls = newval this.urls = newval
// if (this.type && this.type === 'daichong') {
// this.domain = ''
// }
this.imgsUrl = [] this.imgsUrl = []
if (this.urls) { // 判断是否存在 if (this.urls) { // 判断是否存在
if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组 if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组
this.src = this.domain + this.urls this.src = await handleVerAutoImg(this.domain + this.urls)
this.showNoImg = false this.showNoImg = false
} else { } else {
if (this.urls.length) { // 判断是否为空数组 if (this.urls.length) { // 判断是否为空数组
@@ -60,8 +58,8 @@ export default {
} else { } else {
this.showChangeBtn = true this.showChangeBtn = true
} }
this.urls.forEach(item => { this.urls.forEach(async item => {
this.imgsUrl.push(this.domain + item) this.imgsUrl.push(await handleVerAutoImg(this.domain + this.urls))
}) })
this.src = this.imgsUrl[0] this.src = this.imgsUrl[0]
this.showNoImg = false this.showNoImg = false
@@ -75,11 +73,11 @@ export default {
} }
} }
}, },
mounted() { async mounted() {
this.imgsUrl = [] this.imgsUrl = []
if (this.urls) { // 判断是否存在 if (this.urls) { // 判断是否存在
if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组 if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组
this.src = this.domain + this.urls this.src = await handleVerAutoImg(this.domain + this.urls)
} else { } else {
if (this.urls.length) { // 判断是否为空数组 if (this.urls.length) { // 判断是否为空数组
if (this.urls.length === 1) { // 判断数组中是否只有一张图片 if (this.urls.length === 1) { // 判断数组中是否只有一张图片
@@ -87,8 +85,8 @@ export default {
} else { } else {
this.showChangeBtn = true this.showChangeBtn = true
} }
this.urls.forEach(item => { this.urls.forEach(async item => {
this.imgsUrl.push(this.domain + item) this.imgsUrl.push(await handleVerAutoImg(this.domain + item))
}) })
this.src = this.imgsUrl[0] this.src = this.imgsUrl[0]
} else { } else {
@@ -118,12 +116,12 @@ export default {
} }
}, },
// 查看媒体 // 查看媒体
checkMedia() { async checkMedia() {
if (this.urls) { // 判断是否存在 if (this.urls) { // 判断是否存在
if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组 if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组
this.$refs.dialog.open(this.domain + this.urls, 'img') this.$refs.dialog.open(await handleVerAutoImg(this.domain + this.urls), 'img')
} else { } else {
this.$refs.dialog.open(this.urls, 'img') this.$refs.dialog.open(this.imgsUrl, 'img')
} }
} }
} }
+26 -8
View File
@@ -14,12 +14,12 @@
<span>视频时长:{{ this.myData.playTime + "s" }}</span> <span>视频时长:{{ this.myData.playTime + "s" }}</span>
</div> </div>
<!-- <div class="media-box" id="media-box"></div> --> <!-- <div class="media-box" id="media-box"></div> -->
<div v-if="mediaUrl" style="width: 400px; heigth: 130px; background: red;margin-top:10px"> <div v-if="mediaUrl" style="width: 100%; heigth: 200px; background: red">
<DPlayer <DPlayer
ref="player" ref="player"
:video="{ :video="{
url: mediaUrl, url: mediaUrl,
type: type === 'mp4' ? '' : 'hls', type: type=== 'mp4' ?'':'hls',
pic: '', pic: '',
}" }"
hotkey hotkey
@@ -53,7 +53,7 @@ export default {
title: '封面图查看', title: '封面图查看',
params: {}, params: {},
myData: {}, myData: {},
type: undefined, type: undefined,
domain: '/api/web/media/m3u8/' // 存放图片的域名 domain: '/api/web/media/m3u8/' // 存放图片的域名
} }
}, },
@@ -79,6 +79,7 @@ export default {
// 视频审查列表 // 视频审查列表
videoFeviewList() { videoFeviewList() {
videoFeviewList(this.params, this.id).then((res) => { videoFeviewList(this.params, this.id).then((res) => {
// this.myData = res.data, // this.myData = res.data,
}) })
}, },
@@ -93,18 +94,35 @@ export default {
this.myData = { ...data } this.myData = { ...data }
this.dialogVisible = true this.dialogVisible = true
this.title = '视频查看' this.title = '视频查看'
this.mediaUrl = if (url.indexOf('mp4') !== -1) {
this.domain + (url.match(RegExp(/.m3u8/)) ? url : url + '.m3u8') this.mediaUrl = this.$store.getters.getSystemConfig.mp4Url + url
if (url.indexOf('mp4') !== -1) {
this.mediaUrl = this.$store.getters.getSystemConfig.webImgReq + url
this.type = 'mp4' this.type = 'mp4'
} else { } else {
this.mediaUrl = this.mediaUrl =
this.domain + (url.match(RegExp(/.m3u8/)) ? url : url + '.m3u8') this.domain + (url.match(RegExp(/.m3u8/)) ? url : url + '.m3u8')
this.videoFeviewList() this.videoFeviewList()
} }
// + '&token=' + this.token
// this.id = id;
// this.$nextTick(function () {
// document.getElementById("media-box").innerHTML =
// '<video id="my-video" class="video-js vjs-default-skin" controls preload="auto" style="width:100%;height:100%"></video>';
// this.player = videojs(
// "my-video",
// {
// bigPlayButton: false,
// textTrackDisplay: false,
// posterImage: true,
// errorDisplay: true,
// controlBar: true,
// },
// function () {
// this.play();
// }
// );
// this.player.src(this.mediaUrl);
// });
} }
} }
} }
+50 -18
View File
@@ -2,28 +2,35 @@
* @Author: 王涛 * @Author: 王涛
* @Mail: no * @Mail: no
* @Date: 2020-09-29 19:56:44 * @Date: 2020-09-29 19:56:44
* @LastEditors: Please set LastEditors * @LastEditors: Administrator admin@example.com
* @LastEditTime: 2022-06-21 20:05:54 * @LastEditTime: 2024-11-19 10:14:08
--> -->
<template> <template>
<!-- 使用方法 <UploadImg @changeImgUrl='changeMobileAvatar' :img='form.mobileAvatar' :width='"100px"' :height='"100px"'></UploadImg> <!-- 使用方法 <UploadImg @changeImgUrl='changeMobileAvatar' :img='form.mobileAvatar' :width='"100px"' :height='"100px"'></UploadImg>
changeMobileAvatar(data) { changeMobileAvatar(data) {
this.form.mobileAvatar = data this.form.mobileAvatar = data
}, --> }, -->
<el-upload class="avatar-uploader" action="/api/web/file/uploadImg" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"> <el-upload
class="avatar-uploader"
action="/api/web/file/uploadImg"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<div ref="uploader"> <div ref="uploader">
<img v-if="imageUrl" :src="domain + imageUrl" class="avatar" /> <img v-if="newImg" :src="newImg" class="avatar" />
<i v-if="imageUrl" @click.stop="handleRemove" class="el-icon-delete"></i> <i v-if="imageUrl" @click.stop="handleRemove" class="el-icon-delete"></i>
<i v-else class="el-icon-plus avatar-uploader-icon"></i> <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</div> </div>
</el-upload> </el-upload>
</template> </template>
<script> <script>
import { handleVerAutoImg } from '@/utils/index.js'
export default { export default {
data() { data() {
return { return {
domain: this.$store.getters.getSystemConfig.webImgReq, domain: this.$store.getters.getSystemConfig.webImgReq,
imageUrl: '' imageUrl: '',
newImg: ''
} }
}, },
props: { props: {
@@ -38,11 +45,23 @@ export default {
height: { height: {
type: String, type: String,
default: '180px' default: '180px'
},
index: {
type: Number,
default: 0
},
showIndex: {
type: Boolean,
default: false
} }
}, },
watch: { watch: {
img: function(val, oldval) { img: function(val, oldval) {
this.imageUrl = val this.imageUrl = val
},
imageUrl: async function(val, oldval) {
const a = await handleVerAutoImg(this.domain + val)
this.newImg = a
} }
}, },
mounted() { mounted() {
@@ -56,6 +75,9 @@ export default {
} }
}, },
methods: { methods: {
async changeImg(url) {
},
handleAvatarSuccess(res, file) { handleAvatarSuccess(res, file) {
if (res.code === 200) { if (res.code === 200) {
this.$message({ this.$message({
@@ -74,11 +96,19 @@ export default {
} }
}, },
changeImgUrl() { changeImgUrl() {
this.$emit('changeImgUrl', this.imageUrl) if (this.showIndex) {
this.$emit('changeImgUrl', { url: this.imageUrl, index: this.index })
} else {
this.$emit('changeImgUrl', this.imageUrl)
}
}, },
handleRemove(f) { handleRemove(f) {
this.imageUrl = '' this.imageUrl = ''
this.$emit('onRemove', f) if (this.showIndex) {
this.$emit('onRemove', { key: f, index: this.index })
} else {
this.$emit('onRemove', f)
}
}, },
// 上传前进行压缩 // 上传前进行压缩
beforeAvatarUpload(file) { beforeAvatarUpload(file) {
@@ -100,7 +130,7 @@ export default {
// message: '上传图片大小不能超过 2MB!!' // message: '上传图片大小不能超过 2MB!!'
// }) // })
// } // }
return isJPG return isJPG
}, },
// 图片等比压缩 // 图片等比压缩
@@ -142,19 +172,21 @@ export default {
} }
</script> </script>
<style scoped> <style scoped>
.avatar-uploader .el-upload { .avatar-uploader {
border: 1px dashed #d9d9d9; .el-upload {
border-radius: 6px; border: 1px dashed #d9d9d9;
cursor: pointer; border-radius: 6px;
position: relative; cursor: pointer;
overflow: hidden; position: relative;
} overflow: hidden;
.avatar-uploader .el-upload:hover { }
border-color: #409eff; .el-upload:hover {
border-color: #409eff;
}
} }
.avatar-uploader-icon { .avatar-uploader-icon {
font-size: 28px; font-size: 28px;
color: #8c939d; color: #d9d9d9;
width: 100%; width: 100%;
height: 100%; height: 100%;
line-height: 100%; line-height: 100%;
+16 -4
View File
@@ -9,11 +9,11 @@
<div> <div>
<draggable v-model="locaImg" class="list-group" tag="ul" v-bind="dragOptions" @start="drag = true" @end="drag = false"> <draggable v-model="locaImg" class="list-group" tag="ul" v-bind="dragOptions" @start="drag = true" @end="drag = false">
<div v-for="(img,index) in locaImg" :key="index" class="image-list" style="float: left;"> <div v-for="(img,index) in locaImg" :key="index" class="image-list" style="float: left;">
<img class="el-upload-list__item-thumbnail image-detail" :src="domain+img" alt=""> <img class="el-upload-list__item-thumbnail image-detail" :src="imgSrc[index]" alt="">
<!-- 遮罩层 --> <!-- 遮罩层 -->
<a href="#"> <a href="#">
<div class="image-mask"> <div class="image-mask">
<span class="add" @click="handlePictureCardPreview(domain+img)"> <span class="add" @click="handlePictureCardPreview(imgSrc[index])">
<i class="el-icon-view"></i> <i class="el-icon-view"></i>
</span> </span>
<span class="delete" @click="removeImage(index)"> <span class="delete" @click="removeImage(index)">
@@ -33,6 +33,7 @@
</template> </template>
<script> <script>
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import { handleVerAutoImg } from '@/utils/index.js'
export default { export default {
components: { draggable }, components: { draggable },
data() { data() {
@@ -46,7 +47,8 @@ export default {
// { name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100' } // { name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100' }
], ],
drag: false, // 拖拽效果是否开启 drag: false, // 拖拽效果是否开启
locaImg: [] locaImg: [],
imgSrc: []
} }
}, },
props: { props: {
@@ -57,6 +59,7 @@ export default {
} }
} }
}, },
computed: { computed: {
dragOptions() { dragOptions() {
return { return {
@@ -66,6 +69,7 @@ export default {
ghostClass: 'ghost' ghostClass: 'ghost'
} }
} }
}, },
watch: { watch: {
// 监听拖动事件改变时,传出新的图片数组 // 监听拖动事件改变时,传出新的图片数组
@@ -80,15 +84,23 @@ export default {
} }
}, },
mounted() { async mounted() {
this.locaImg = [] this.locaImg = []
if (this.img) { if (this.img) {
this.img.filter((item) => { this.img.filter((item) => {
this.locaImg.push(item) this.locaImg.push(item)
}) })
} }
// 在组件挂载时加载图像 URL
this.imgSrc = await Promise.all(this.locaImg.map(img => this.changeImg(img)))
}, },
methods: { methods: {
async changeImg(img) {
// 这里应该替换为真实的异步代码
const a = await handleVerAutoImg(this.domain + img)
return a
},
handleChange(file, fileList) { handleChange(file, fileList) {
if (file.status === 'success') { if (file.status === 'success') {
this.locaImg.push(file.response.data.path) this.locaImg.push(file.response.data.path)
+8 -1
View File
@@ -8,7 +8,7 @@
<template> <template>
<div class="box"> <div class="box">
<div v-on:paste="handlePaste" v-drag="handleDrag" > <div v-on:paste="handlePaste" v-drag="handleDrag" >
<img v-if='imageUrl' ref="preview" :src="domain+imageUrl" alt="" style="width:300px;height:300px;"> <img v-if='newImg' ref="preview" :src="newImg" alt="" style="width:300px;height:300px;">
<div v-else style="width:300px;height:300px;border:1px solid;padding:20px;"> <div v-else style="width:300px;height:300px;border:1px solid;padding:20px;">
<div style="text-indent:2em;">将图片按<span style="color:red">cmd+C复制</span>到粘贴板<span style="color:red">cmd+V粘贴</span>至此处</div> <div style="text-indent:2em;">将图片按<span style="color:red">cmd+C复制</span>到粘贴板<span style="color:red">cmd+V粘贴</span>至此处</div>
<div style="text-indent:2em;">或者将图片拖拽至此处</div> <div style="text-indent:2em;">或者将图片拖拽至此处</div>
@@ -18,6 +18,8 @@
</template> </template>
<script> <script>
import { mediaUploadImg } from '@/api/components/UploadImgPaste' import { mediaUploadImg } from '@/api/components/UploadImgPaste'
import { handleVerAutoImg } from '@/utils/index.js'
export default { export default {
data() { data() {
return { return {
@@ -34,6 +36,10 @@ export default {
watch: { watch: {
img: function(val) { img: function(val) {
this.imageUrl = val this.imageUrl = val
},
imageUrl: async function(val, oldval) {
const a = await handleVerAutoImg(this.domain + val)
this.newImg = a
} }
}, },
mounted() { mounted() {
@@ -44,6 +50,7 @@ export default {
} }
}, },
methods: { methods: {
handleDrag(event) { handleDrag(event) {
const items = Array.from(event.dataTransfer.items) const items = Array.from(event.dataTransfer.items)
let file = null let file = null
+22
View File
@@ -0,0 +1,22 @@
import { getSyscfg } from '@/api/system/systemConfig'
import { getToken } from '@/utils/auth'
export default {
methods: {
async getSyscfg() {
const tk = getToken()
if (!tk) return
try {
const res = await getSyscfg({})
if (res.code === 200) {
this.form = res.data
this.$store.dispatch('system/setConfig', res.data)
} else {
this.$message.error('请求系统配置失败')
}
} catch (error) {
console.error('get syscfg error:::', error)
}
}
}
}
+3 -3
View File
@@ -2,8 +2,8 @@
* @Author: 王涛 * @Author: 王涛
* @Mail: no * @Mail: no
* @Date: 2020-10-10 14:27:58 * @Date: 2020-10-10 14:27:58
* @LastEditors: Please set LastEditors * @LastEditors: 江涛
* @LastEditTime: 2022-03-14 15:29:54 * @LastEditTime: 2021-03-24 19:34:23
*/ */
const state = { const state = {
config: { config: {
@@ -15,7 +15,7 @@ const state = {
driverGroup: undefined, // 开车群 driverGroup: undefined, // 开车群
headerM3U8: undefined, // 片头m3u8 headerM3U8: undefined, // 片头m3u8
id: 0, id: 0,
webImgReq: 'http://resourceyuan.bbaazz.me/', // 图片请求域名(web使用) webImgReq: '', // 图片请求域名(web使用)
imgReq: undefined, // 图片请求域名(app使用) imgReq: undefined, // 图片请求域名(app使用)
imgUpload: undefined, // 图片上传地址 imgUpload: undefined, // 图片上传地址
inviteAddr: undefined, // 用户邀请地址 inviteAddr: undefined, // 用户邀请地址
+102
View File
@@ -0,0 +1,102 @@
// import { Buffer } from 'buffer/'
// 判断是否加解密,如果字节前几位对应上,则不需要解密
const encryptMagicNumber = new Uint8Array([
0x88,
0xA8,
0x30,
0xCB,
0x10,
0x76
])
// 解密密钥
// const _decryptKey = Buffer.from('2019ysapp7527') // 加密key
// 避免vite单独引入buffer库 提前进行编码
const _decryptKey = [50, 48, 49, 57, 121, 115, 97, 112, 112, 55, 53, 50, 55]// 加密key
const _encryptedLen = 100 // 加密图片的数据长度
// / 加密密钥(????,不解就去找游总解答)
const ENCRYPT_KEY = 0xA3
// 三种图片 type类型,根据前几子节可以判断出类型,这是固定的。如需要增加其他类型则自己上网找固定对应的字节。
const _featuresList = [
new Uint8Array([0xFF, 0xD8, 0xFF]), // jpg,jpeg
new Uint8Array([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]), // png
new Uint8Array([0x47, 0x49, 0x46]) // gif
]
/**
* 解密入口
*/
export function decryptImage(imgBytes) {
// 判断是否为空,如果传入的字节为空则不处理
if (imgBytes === null || imgBytes.length === 0) { return }
// 增加一个变量来判断是否存在
let isAll = false
// 循环魔法密钥,确定这是需要解密的图片是全部长度,而不是前100字节
for (let i = 0; i < encryptMagicNumber.length; i++) {
if (encryptMagicNumber[i] !== imgBytes[i]) { continue }
isAll = true
}
if (isAll) {
imgBytes = xorBaseAllLength(imgBytes)
} else {
// 是需要解密的
if (isEncryptedImage(imgBytes)) {
// 解密结果
imgBytes = xorBaseLength(imgBytes, _decryptKey, _encryptedLen)
}
}
return imgBytes
}
/**
* 返回一个判断值,true则代表 是png gif jpg三种图片中的一种,则需要解密
*/
function isEncryptedImage(imgBytes) {
let isDecrypted = false
const _featuresLen = _featuresList.length
for (let i = 0; i < _featuresLen; i++) {
// 每次进入则初始化变量的值为假
isDecrypted = false
for (let j = 0; j < _featuresList[i].length; j++) {
if (_featuresList[i][j] !== imgBytes[j]) {
isDecrypted = true
break
}
}
if (isDecrypted) { continue } else { break }
}
return isDecrypted
}
// 解密算法
function xorBaseLength(src, key, length) {
const srcLen = src.length
const keyLen = key.length
if (length > srcLen || length <= 0) { length = srcLen }
for (let i = 0; i < length; i += keyLen) {
for (let j = 0; j < keyLen && i + j < length; j++) { src[i + j] ^= key[j] }
}
return src
}
// 全部长度解密,解密算法
function xorBaseAllLength(src) {
let index = -1
// 这里map数组内 所有的字节做位异或运数,返回的是解密后的数组
const dest = src.map((it) => {
index++
if (
index < encryptMagicNumber.length &&
it === encryptMagicNumber[index]
) { return null }
return it ^ ENCRYPT_KEY
})
return dest
}
+86 -1
View File
@@ -1,7 +1,7 @@
/** /**
* Created by PanJiaChen on 16/11/18. * Created by PanJiaChen on 16/11/18.
*/ */
import { decryptImage } from './imgCode.js'
/** /**
* Parse the time to string * Parse the time to string
* @param {(Object|string|number)} time * @param {(Object|string|number)} time
@@ -227,3 +227,88 @@ export function getQueryString(name) {
} }
return null return null
} }
export async function handleVerAutoImg(imageUrl) {
// 参数校验
if (!imageUrl || typeof imageUrl !== 'string') {
console.warn('无效的图片URL:', imageUrl)
return imageUrl // 返回原始URL
}
// 检查URL是否已经是Blob URL
if (imageUrl.startsWith('blob:')) {
return imageUrl
}
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10秒超时
const response = await fetch(imageUrl, {
signal: controller.signal,
headers: {
'Accept': 'image/*'
}
}).finally(() => clearTimeout(timeoutId))
if (!response.ok) {
console.warn(`图片加载失败: ${response.status} ${response.statusText}`)
return imageUrl // 返回原始URL
}
const arrayBuffer = await response.arrayBuffer()
const bytes = new Uint8Array(arrayBuffer)
// 基本验证:检查是否为有效的图片数据
if (bytes.length === 0) {
// console.warn('图片数据为空')
return imageUrl
}
try {
// 尝试解密图片数据
const decryptedData = decryptImage(bytes)
// 验证解密后的数据
if (!decryptedData || decryptedData.length === 0) {
// console.warn('图片解密结果无效')
return imageUrl
}
// 创建Blob URL前检查数据有效性
const blob = new Blob([decryptedData], { type: 'image/jpeg' })
if (blob.size === 0) {
// console.warn('解密后的图片数据为空')
return imageUrl
}
const blobUrl = URL.createObjectURL(blob)
// 添加清理逻辑
window.addEventListener('unload', () => {
try {
URL.revokeObjectURL(blobUrl)
} catch (e) {
// 忽略清理错误
console.log(e, 'e')
}
})
return blobUrl
} catch (decryptError) {
console.warn('图片解密失败,使用原始URL:', decryptError)
return imageUrl
}
} catch (error) {
// 处理特定类型的错误
if (error.name === 'AbortError') {
// console.warn('图片加载超时')
} else if (error instanceof TypeError) {
// console.warn('网络请求失败')
} else {
// console.warn('图片处理失败:', error)
}
// 返回原始URL而不是抛出错误
return imageUrl
}
}
@@ -1,25 +1,45 @@
<template> <template>
<el-dialog :title="title" :visible.sync="Visible" width="780px" center class="ac-dialog" :close-on-click-modal="false" <el-dialog
:title="title"
:visible.sync="Visible"
width="780px"
center
class="ac-dialog"
:close-on-click-modal="false"
@close="close"> @close="close">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col > <el-col >
<h3>AI生成的视频URl</h3> <h3>AI生成的视频URl</h3>
<div v-if="form.vidUrl" style="width: 380px; height: 240px; overflow: hidden"> <div v-if="form.vidUrl" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer ref="player" v-if="form.vidUrl.indexOf('mp4') === -1" :video="{ <DPlayer
ref="player"
v-if="form.vidUrl.indexOf('mp4') === -1"
:video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.vidUrl), url: '/api/web/media/m3u8/' + filterM3u8(form.vidUrl),
type: 'hls', type: 'hls',
pic: '', pic: '',
}" hotkey ></DPlayer> }"
<DPlayer ref="player" v-else :video="{ hotkey ></DPlayer>
url: this.$store.getters.getSystemConfig.webImgReq + form.vidUrl, <DPlayer
ref="player"
v-else
:video="{
url: this.$store.getters.getSystemConfig.mp4Url + form.vidUrl,
type: 'mp4', type: 'mp4',
pic: '', pic: '',
}" hotkey ></DPlayer> }"
hotkey ></DPlayer>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-form :inline="true" :model="form" :rules="rules" ref="form" class="demo-form-inline" label-width="120px" <el-form
:inline="true"
:model="form"
:rules="rules"
ref="form"
class="demo-form-inline"
label-width="120px"
label-position="right"> label-position="right">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12"> <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
@@ -43,8 +63,7 @@
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="Visible = false"> </el-button> <el-button @click="Visible = false"> </el-button>
<el-button type="primary" @click="submit('form')"> </el-button> <el-button type="primary" @click="submit('form')"> </el-button>
@@ -76,15 +95,15 @@ export default {
formData: {}, formData: {},
// 表单数据 // 表单数据
form: { form: {
"byWay": undefined, 'byWay': undefined,
"id": undefined, 'id': undefined,
"modifyImgs": undefined, 'modifyImgs': undefined,
"vidUrl": undefined, 'vidUrl': undefined,
"reason": undefined, 'reason': undefined,
"status": 0, 'status': 0,
"updatedAt": undefined 'updatedAt': undefined
}, },
rules: {}, rules: {}
} }
}, },
mounted() { mounted() {
@@ -95,22 +114,20 @@ export default {
} }
}, },
methods: { methods: {
//TODO:新增应用列表数据 // TODO:新增应用列表数据
filterM3u8(v) { filterM3u8(v) {
return /\.m3u8/g.test(v) ? v : v + '.m3u8' return /\.m3u8/g.test(v) ? v : v + '.m3u8'
}, },
//TODO:编辑应用列表数据 // TODO:编辑应用列表数据
update(data) { update(data) {
aiorderFacechangeUpdate(data).then((res) => { aiorderFacechangeUpdate(data).then((res) => {
if (res && res.code === 200) { if (res && res.code === 200) {
this.$message.success(res.data ? res.data : '更新成功') this.$message.success(res.data ? res.data : '更新成功')
} else { } else {
this.$message.error(res.data ? res.data : '更新失败') this.$message.error(res.data ? res.data : '更新失败')
} }
this.Visible = false this.Visible = false
}) })
}, },
// 提交按钮 // 提交按钮
@@ -145,16 +162,16 @@ export default {
changeCoverImgUrl(data) { changeCoverImgUrl(data) {
this.form.modifyImgs = data this.form.modifyImgs = data
}, },
// 关闭编辑 // 关闭编辑
close() { close() {
this.$emit('close') this.$emit('close')
}, },
onClear(data) { onClear(data) {
this.form[data] = undefined this.form[data] = undefined
}, }
}, }
} }
</script> </script>
@@ -1,26 +1,46 @@
<template> <template>
<el-dialog :title="title" :visible.sync="Visible" width="780px" center class="ac-dialog" :close-on-click-modal="false" <el-dialog
:title="title"
:visible.sync="Visible"
width="780px"
center
class="ac-dialog"
:close-on-click-modal="false"
@close="close"> @close="close">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col> <el-col>
<h3>AI生成的视频URl</h3> <h3>AI生成的视频URl</h3>
<div v-if="form.modifyVideoUrl" style="width: 380px; height: 240px; overflow: hidden"> <div v-if="form.modifyVideoUrl" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer ref="player" v-if="form.modifyVideoUrl.indexOf('mp4') === -1" :video="{ <DPlayer
ref="player"
v-if="form.modifyVideoUrl.indexOf('mp4') === -1"
:video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.modifyVideoUrl), url: '/api/web/media/m3u8/' + filterM3u8(form.modifyVideoUrl),
type: 'hls', type: 'hls',
pic: '', pic: '',
}" hotkey ></DPlayer> }"
<DPlayer ref="player" v-else :video="{ hotkey ></DPlayer>
url: this.$store.getters.getSystemConfig.webImgReq + form.modifyVideoUrl, <DPlayer
ref="player"
v-else
:video="{
url: this.$store.getters.getSystemConfig.mp4Url + form.modifyVideoUrl,
type: 'mp4', type: 'mp4',
pic: '', pic: '',
}" hotkey ></DPlayer> }"
hotkey ></DPlayer>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-form :inline="true" :model="form" :rules="rules" ref="form" class="demo-form-inline" label-width="120px" <el-form
:inline="true"
:model="form"
:rules="rules"
ref="form"
class="demo-form-inline"
label-width="120px"
label-position="right"> label-position="right">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12"> <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
@@ -31,7 +51,10 @@
<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12"> <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="换脸方式"> <el-form-item label="换脸方式">
<el-select placeholder="请选择换脸方式" clearable v-model="form.byWay"> <el-select placeholder="请选择换脸方式" clearable v-model="form.byWay">
<el-option :key="item.value" :label="item.label" :value="item.value" <el-option
:key="item.value"
:label="item.label"
:value="item.value"
v-for="item in aiOrderFaceChangeList" /> v-for="item in aiOrderFaceChangeList" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -51,7 +74,6 @@
</el-row> </el-row>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="Visible = false"> </el-button> <el-button @click="Visible = false"> </el-button>
<el-button type="primary" @click="submit('form')"> </el-button> <el-button type="primary" @click="submit('form')"> </el-button>
@@ -83,15 +105,15 @@ export default {
formData: {}, formData: {},
// 表单数据 // 表单数据
form: { form: {
"byWay": undefined, 'byWay': undefined,
"id": undefined, 'id': undefined,
"modifyImgs": undefined, 'modifyImgs': undefined,
"modifyVideoUrl": undefined, 'modifyVideoUrl': undefined,
"reason": undefined, 'reason': undefined,
"status": 0, 'status': 0,
"updatedAt": undefined 'updatedAt': undefined
}, },
rules: {}, rules: {}
} }
}, },
mounted() { mounted() {
@@ -102,18 +124,15 @@ export default {
} }
}, },
methods: { methods: {
//TODO:新增应用列表数据 // TODO:新增应用列表数据
filterM3u8(v) { filterM3u8(v) {
return /\.m3u8/g.test(v) ? v : v + '.m3u8' return /\.m3u8/g.test(v) ? v : v + '.m3u8'
}, },
//TODO:编辑应用列表数据 // TODO:编辑应用列表数据
update(data) { update(data) {
aiorderStripUpdate(data).then((res) => { aiorderStripUpdate(data).then((res) => {
if (res && res.code === 200) {
if (res && res.code === 200) {
this.$message.success(res.data ? res.data : '更新成功') this.$message.success(res.data ? res.data : '更新成功')
} else { } else {
this.$message.error(res.data ? res.data : '更新失败') this.$message.error(res.data ? res.data : '更新失败')
@@ -161,8 +180,8 @@ export default {
onClear(data) { onClear(data) {
this.form[data] = undefined this.form[data] = undefined
}, }
}, }
} }
</script> </script>
@@ -1,159 +1,129 @@
<template> <template>
<el-dialog :title="title" :visible.sync="Visible" width="1800px" center class="ac-dialog" :close-on-click-modal="false" @close="close"> <el-dialog
:title="title"
:visible.sync="Visible"
width="1800px"
center
class="ac-dialog"
:close-on-click-modal="false"
@close="close">
<el-form :inline="true" :model="form" class="demo-form-inline" label-width="120px" label-position="right"> <el-form :inline="true" :model="form" class="demo-form-inline" label-width="120px" label-position="right">
<el-row :gutter="24"> <div>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"> <el-form-item label="标题">
<el-form-item label="标题"> <el-input v-model="form.title" style="width: 315px" />
<el-input v-model="form.title" style="width: 315px" /> </el-form-item>
</el-form-item> </div>
</el-col> <div>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"> <el-form-item label="封面">
<el-form-item label="封面类型"> <UploadImg @changeImgUrl="changeCoverImgUrl" :img="form.coverImg" @onRemove="handleRemove('coverImg')">
<el-select style="width: 180px" placeholder="请选择封面类型" v-model="form.coverType"> </UploadImg>
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in coverTypeList" /> </el-form-item>
</el-select> </div>
</el-form-item> <el-form-item label="影片类型">
</el-col> <el-select clearable placeholder="影片类型" v-model="form.type" style="width: 180px">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"> <el-option label="长视频" value="longvideo" />
<el-form-item label="视频归类"> <el-option label="视频" value="shortvideo" />
</el-select>
</el-form-item>
<el-form-item label="视频归类">
<el-select placeholder="请选择视频归类" v-model="videoType" style="width: 180px"> <el-select placeholder="请选择视频归类" v-model="videoType" style="width: 180px">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in formVideoTypeList" /> <el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in formVideoTypeList" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> <div>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"> <el-form-item label="APP">
<el-form-item label="封面"> <el-select multiple placeholder="APP" v-model="form.appids" style="width: 180px">
<UploadImg @changeImgUrl="changeCoverImgUrl" :img="form.coverImg"></UploadImg> <el-option label="麻豆APP" :value="1" />
</el-form-item> <el-option label="麻豆官网" :value="2" />
</el-col> <el-option label="逼喱逼喱" :value="3" />
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8"> </el-select>
<el-form-item label="番号"> </el-form-item>
<el-input v-model="form.bango" style="width: 315px" />
</el-form-item>
</el-col>
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="演员">
<el-input v-model="form.actors" placeholder="可填多人,中间用'/。/,'等符号分割" style="width:315px" />
</el-form-item>
</el-col>
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="视频归属">
<el-input v-model="form.mediaSet" style="width: 315px" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="一级标签:">
<el-input v-model="form.firstTag" placeholder="请输入一级标签,中间用'/。/,'等符号分割" style="width:315px" />
</el-form-item>
</el-col>
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="二级标签">
<el-input v-model="form.secondTags" placeholder="请输入二级标签,中间用'/。/,'等符号分割" style="width:315px" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="APP">
<el-select multiple placeholder="APP" v-model="form.appids" style="width: 180px">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in appidsList" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="视频类型">
<el-select placeholder="请选择视频类型" v-model="form.formatType" style="width: 180px">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in formatTypeList" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="内容类型">
<el-select placeholder="请选择内容类型" v-model="form.contentType" style="width: 180px">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in contentTypeList" />
</el-select>
</el-form-item>
</el-col>
<el-col :lg="8" :md="8" :sm="8" :xl="8" :xs="8">
<el-form-item label="发布者">
<el-input v-model="form.publish" placeholder="请输入发布者" style="width: 180px" />
</el-form-item>
</el-col>
<el-col :lg="8" :md="8" :sm="8" :xl="8" :xs="8">
<el-form-item label="所有者">
<el-input v-model="form.studio" placeholder="请输入所有者" style="width: 180px" />
</el-form-item>
</el-col>
<el-col :lg="8" :md="8" :sm="8" :xl="8" :xs="8">
<el-form-item label="上架时间">
<el-date-picker style="width: 180px" v-model="form.addedTime" type="date" placeholder="选择日期" value-format="yyyy-MM-ddTHH:mm:ssZ">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
<el-form-item label="正片地址">
<el-input v-model="form.fieldNameFs" style="width: 515px" disabled="disabled" />
</el-form-item>
</el-col>
<el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
<el-form-item label="预览地址">
<el-input v-model="form.preFileName" style="width: 515px">
<el-button slot="append" @click="innerVisible = true">自定义设置预览</el-button>
</el-input>
</el-form-item>
</el-col>
<el-col :lg="24" :md="24" :sm="24" :xl="24" :xs="24">
<el-form-item label="详细描述">
<el-input v-model="form.desc" type="textarea" style="width: 515px" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div style="position: absolute;top: 50px;right: 50px">
<div style="float:left">
<h3>预览</h3>
<div v-if="form.preFileName" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer ref="player" v-if="form.preFileName.indexOf('mp4') === -1" :video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.preFileName),
type: 'hls',
pic: '',
}" hotkey></DPlayer>
<DPlayer ref="player" v-else :video="{
url: this.$store.getters.getSystemConfig.webImgReq + form.preFileName,
type: 'mp4',
pic: '',
}" hotkey></DPlayer>
</div>
</div> </div>
<div style="float:left"> <div>
<h3>正片</h3> <el-form-item label="上架时间">
<div v-if="form.fieldNameFs" style="width: 380px; height: 240px; overflow: hidden"> <el-date-picker
<DPlayer ref="player" v-if="form.fieldNameFs.indexOf('mp4') === -1" :video="{ style="width: 180px"
url: '/api/web/media/m3u8/' + filterM3u8(form.fieldNameFs), v-model="form.addedTime"
type: 'hls', type="date"
pic: '', placeholder="选择日期"
}" hotkey></DPlayer> value-format="yyyy-MM-ddTHH:mm:ssZ">
<DPlayer ref="player" v-else :video="{ </el-date-picker>
url: this.$store.getters.getSystemConfig.webImgReq + form.fieldNameFs, </el-form-item>
</div>
<div>
<el-form-item label="正片地址">
<el-input v-model="form.fieldNameFs" style="width: 515px" disabled="disabled" />
</el-form-item>
</div>
<div>
<el-form-item label="预览地址">
<el-input v-model="form.preFileName" style="width: 515px">
<el-button slot="append" @click="innerVisible = true">自定义设置预览</el-button>
</el-input>
</el-form-item>
</div>
<el-form-item label="详细描述">
<el-input v-model="form.desc" type="textarea" style="width: 515px" />
</el-form-item>
</el-form>
<div style="position: absolute; top: 50px; right: 10px">
<h3>正片</h3>
<div v-if="form.fieldNameFs" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer
ref="player"
v-if="form.fieldNameFs.indexOf('mp4') === -1"
:video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.fieldNameFs),
type: 'hls',
pic: '',
}"
hotkey></DPlayer>
<DPlayer
ref="player"
v-else
:video="{
url: this.$store.getters.getSystemConfig.mp4Url + form.fieldNameFs,
type: 'mp4', type: 'mp4',
pic: '', pic: '',
}" hotkey></DPlayer> }"
</div> hotkey></DPlayer>
<UploadVideo v-if="videoType" @changeVideoUrl="changeVideoUrl" :type="videoType" @repeatVideo="repeatVideo" </div>
<UploadVideo
v-if="videoType"
@changeVideoUrl="changeVideoUrl"
:type="videoType"
@repeatVideo="repeatVideo"
style="max-width: 520px"></UploadVideo> style="max-width: 520px"></UploadVideo>
<div v-else class="check_upload" @click.prevent="checkUpload"> <div v-else class="check_upload" @click.prevent="checkUpload">
<div> <div>
选择文件 选择文件
</div> </div>
</div> </div>
</div> </div>
<div style="position: absolute; top: 50px; right: 410px">
<h3>预览</h3>
<div v-if="form.preFileName" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer
ref="player"
v-if="form.preFileName.indexOf('mp4') === -1"
:video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.preFileName),
type: 'hls',
pic: '',
}"
hotkey></DPlayer>
<DPlayer
ref="player"
v-else
:video="{
url: this.$store.getters.getSystemConfig.mp4Url + form.preFileName,
type: 'mp4',
pic: '',
}"
hotkey></DPlayer>
</div>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click.native.prevent="Visible = false"> </el-button> <el-button @click.native.prevent="Visible = false"> </el-button>
@@ -169,7 +139,6 @@
: :
<el-input-number :min="0" :max="24" size="mini" v-model="previewTimeData.h"></el-input-number> <el-input-number :min="0" :max="24" size="mini" v-model="previewTimeData.h"></el-input-number>
</div> </div>
<div> <div>
: :
<el-input-number :min="0" :max="59" size="mini" v-model="previewTimeData.m"></el-input-number> <el-input-number :min="0" :max="59" size="mini" v-model="previewTimeData.m"></el-input-number>
@@ -193,68 +162,68 @@
<script> <script>
import DPlayer from '@/components/VueDplayerHls/index' import DPlayer from '@/components/VueDplayerHls/index'
import UploadImg from '@/components/UploadImg/index' import UploadImg from '@/components/UploadImg/index'
import UploadVideo from '@/components/UploadVideoLibrary/index' import UploadVideo from '@/components/UploadVideo/index'
import 'videojs-contrib-hls' import 'videojs-contrib-hls'
import { mediaUpdate, updatePreTime } from '@/api/mediaLibrary/videoList' import { mediaUpdate, updatePreTime } from '@/api/mediaLibrary/videoList'
import { stringToArry, arryToString, current } from '@/filters/index' import { stringToArry, arryToString } from '@/filters/index'
import { import { StatusList, formVideoTypeList } from '@/filters/mediaLibrary/videoList'
coverTypeList, import { current } from '@/filters/index'
appidsList,
formatTypeList,
formVideoTypeList
} from '@/filters/mediaLibrary/videoList'
export default { export default {
name: 'AddOrEdit', name: 'AddOrEdit',
props: ['data','contentTypeList'], props: ['data'],
components: { components: {
UploadImg, UploadImg,
UploadVideo, UploadVideo,
DPlayer, DPlayer
}, },
computed: { computed: {
totalTime() { totalTime() {
return this.data.data.videoTime return this.data.data.videoTime
}, }
}, },
data() { data() {
return { return {
coverTypeList: coverTypeList(),
appidsList: appidsList(),
formatTypeList: formatTypeList(),
formVideoTypeList: formVideoTypeList(),
type: undefined,
videoType: undefined,
innerVisible: false, innerVisible: false,
Visible: true, Visible: true,
title: '', title: '',
defaltTime: current() + 'T12:00:00.000Z', defaltTime: current() + 'T12:00:00.000Z',
taskId: '', taskId: '',
StatusList: StatusList(),
formVideoTypeList: formVideoTypeList(),
tags: null, tags: null,
fieldNameFs: '', // 正片地址全称 fieldNameFs: '', // 正片地址全称
form: { secondTags: [],
formatType: undefined, // 视频类型 1:长视频 2:短视频 3:预览 FirstTagList: [],
mediaSet: undefined, // 视频归属
contentType: undefined, // 内容类型 1:av(日本) 2:国产(短视频) 3:动漫
coverType: undefined, // 封面类型 1:竖版 2:横版 3:系统
title: undefined, // 'string',标题 form: {
addedTime: undefined, // 'string',上架时间
publish: undefined, // 'string',视频发布者
firstTag: undefined, // 'string',一级标签
secondTags: undefined, // [],二级标签标签
bango: undefined, // 'string',番号
appids: [], appids: [],
desc: undefined, // 'string',详细描述
preFileName: undefined, // 'string',预览文件
coverImg: undefined, // 封面
actors: undefined, // [],演员 actors: undefined, // [],演员
addedTime: undefined, // 'string',上架时间
bango: undefined, // 'string',番号
checkSum: undefined, // 'string',md5校验码
country: undefined, // 'string',国家
coverImg: undefined, // 封面
desc: undefined, // 'string',详细描述
directors: undefined, // [],导演
firstTag: undefined, // 'string',一级标签
preFileName: undefined, // 'string',预览文件
preview: undefined, // 0,预览普通视频
publish: undefined, // 'string',视频发布者
secondTags: undefined, // [],二级标签标签
size: undefined, // 0,文件大小
status: undefined, // 'string',当前状态
studio: undefined, // 'string',工作室/所有者 studio: undefined, // 'string',工作室/所有者
title: undefined, // 'string',标题
type: undefined, // 'string',长视频/短视频
videoTime: undefined // 0,影片长度
}, },
previewTimeData: { previewTimeData: {
h: 0, h: 0,
m: 0, m: 0,
s: 0, s: 0
}, },
type: undefined,
videoType: undefined
} }
}, },
@@ -263,8 +232,7 @@ export default {
if (this.title === '编辑') { if (this.title === '编辑') {
this.form = { ...this.data.data } this.form = { ...this.data.data }
this.form.actors = arryToString(this.form.actors) this.form.actors = arryToString(this.form.actors)
this.form.secondTags = arryToString(this.form.secondTags) this.form.directors = arryToString(this.form.directors)
this.form.mediaSet = arryToString(this.form.mediaSet)
if (this.form.fieldNameFs) { if (this.form.fieldNameFs) {
this.open() this.open()
} }
@@ -273,16 +241,44 @@ export default {
this.player.dispose() this.player.dispose()
} }
}, },
methods: { methods: {
checkUpload() { checkUpload() {
if (!this.type) { if (!this.videoType) {
return this.$message({ return this.$message({
type: 'error', type: 'error',
message: '请选择视频归类!!' message: '请选择视频归类!!'
}) })
} }
}, },
//TODO:编辑影片列表数据 // TODO:新增视频时绑定煤资库ID
async subimitPTime() {
let s = 0
if (this.previewTimeData.h) {
s += this.previewTimeData.h * 60 * 60
}
if (this.previewTimeData.m) {
s += this.previewTimeData.m * 60
}
s += this.previewTimeData.s
if (s > 0 && s + 15 <= this.data.data.videoTime - 15) {
const data = {
id: this.data.data.id,
preFileTime: s
}
updatePreTime(data).then((res) => {
if (res.code === 200) {
this.$message.success('预览时长设置成功')
this.innerVisible = false
} else {
this.$message.error('预览时长设置失败')
}
})
} else {
this.$message.error('预览时长设置不能为零或不能超过播放时长')
}
},
// TODO:提交视频列表数据
update(data) { update(data) {
mediaUpdate(data).then((res) => { mediaUpdate(data).then((res) => {
if (res.code === 200) { if (res.code === 200) {
@@ -296,6 +292,9 @@ export default {
filterM3u8(v) { filterM3u8(v) {
return /\.m3u8/g.test(v) ? v : v + '.m3u8' return /\.m3u8/g.test(v) ? v : v + '.m3u8'
}, },
handleRemove(key) {
this.form[key] = ''
},
// 清空某一项筛选列表 // 清空某一项筛选列表
onClear(key) { onClear(key) {
this.form.param[key] = [] this.form.param[key] = []
@@ -304,57 +303,52 @@ export default {
this.previewTimeData = { this.previewTimeData = {
h: 0, h: 0,
m: 0, m: 0,
s: 0, s: 0
} }
this.innerVisible = false this.innerVisible = false
}, },
async subimitPTime() {
let s = 0
if (this.previewTimeData.h) {
s += this.previewTimeData.h * 60 * 60
}
if (this.previewTimeData.m) {
s += this.previewTimeData.m * 60
}
s += this.previewTimeData.s
if (s > 0 && s + 15 <= this.data.data.videoTime - 15) {
const res = await updatePreTime({
id: this.data.data.id,
preFileTime: s,
})
if (res.code === 200) {
this.$message.success('预览时长设置成功')
this.innerVisible = false
} else {
this.$message.error('预览时长设置失败')
}
} else {
this.$message.error('预览时长设置不能为零或不能超过播放时长')
}
},
// 提交按钮 // 提交按钮
submit() { submit() {
const data = { ...this.form } const data = { ...this.form }
data.actors = data.actors ? stringToArry(data.actors) : [] data.actors = data.actors ? stringToArry(data.actors) : []
data.secondTags = data.secondTags ? stringToArry(data.secondTags) : [] data.directors = data.directors ? stringToArry(data.directors) : []
data.mediaSet = data.mediaSet ? stringToArry(data.mediaSet) : [] const YY = new Date().getUTCFullYear()
data.addedTime = data.addedTime const MM =
? data.addedTime === '0001-01-01T00:00:00Z' new Date().getMonth() + 1 < 10
? this.defaltTime ? `0${new Date().getMonth() + 1}`
: data.addedTime : new Date().getMonth() + 1
: this.defaltTime const DD =
new Date().getUTCDate() < 10
? `0${new Date().getUTCDate()}`
: new Date().getUTCDate()
const HH =
new Date().getUTCHours() < 10
? `0${new Date().getUTCHours()}`
: new Date().getUTCHours()
const MU =
new Date().getUTCMinutes() < 10
? `0${new Date().getUTCMinutes()}`
: new Date().getUTCMinutes()
const SS =
new Date().getUTCSeconds() < 10
? `0${new Date().getUTCSeconds()}`
: new Date().getUTCSeconds()
const MS =
new Date().getUTCMilliseconds() < 10
? `0${new Date().getUTCMilliseconds()}`
: new Date().getUTCMilliseconds()
data.addedTime =
data.addedTime || `${YY}-${MM}-${DD}T${HH}:${MU}:${SS}.${MS}Z`
this.update(data) this.update(data)
}, },
// 上传视频返回地址 // 上传视频返回地址
changeVideoUrl(data) { changeVideoUrl(data) {
this.form.id = data.id this.form.id = data.id
// this.$set(this.form, 'fieldNameFs', data.videoUri)
this.fieldNameFs = data.videoUri this.fieldNameFs = data.videoUri
// this.form.fieldNameFs = data.videoUri this.form.videoTime = parseInt(data.duration)
// this.form.videoTime = parseInt(data.duration) this.form.size = data.size
// this.form.size = data.size
// this.open()
}, },
// 重复上传视频 // 重复上传视频
@@ -368,36 +362,23 @@ export default {
this.form.coverImg = data this.form.coverImg = data
}, },
// / 监听视频播放的回调函数 // / 监听视频播放的回调函数
onPlayerPlay() {}, onPlayerPlay() { },
// / 监听暂停播放的回调函数 // / 监听暂停播放的回调函数
onPlayerPause() {}, onPlayerPause() { },
// / 监听当前视频数据加载完成 // / 监听当前视频数据加载完成
onPlayerLoadeddata() {}, onPlayerLoadeddata() { },
// / 监听当前视频数据加载失败 // / 监听当前视频数据加载失败
onPlayerError() {}, onPlayerError() { },
// / 监听当前视频数据加载ing // / 监听当前视频数据加载ing
onPlayerWaiting() {}, onPlayerWaiting() { },
// / 监听当前视频播放完成 // / 监听当前视频播放完成
onPlayerEnded() {}, onPlayerEnded() { },
open() { open() {
this.mediaUrl = this.mediaUrl =
'api/web/media/m3u8/' + 'api/web/media/m3u8' +
(this.form.fieldNameFs.match(RegExp(/.m3u8/)) (this.form.fieldNameFs.match(RegExp(/.m3u8/))
? this.form.fieldNameFs ? this.form.fieldNameFs
: this.form.fieldNameFs + '.m3u8') : this.form.fieldNameFs + '.m3u8')
// this.$nextTick(function () {
// document.getElementById("media-box").innerHTML =
// '<video id="my-video" class="video-js vjs-default-skin" controls preload="auto" style="width:100%;height:100%; " playsinline="true"></video>';
// this.player = videojs("my-video", {
// bigPlayButton: false,
// textTrackDisplay: false,
// posterImage: true,
// errorDisplay: true,
// controlBar: true,
// playbackRates: [0.5, 1, 1.5, 2, 3, 5, 10],
// });
// this.player.src(this.mediaUrl);
// });
}, },
// 关闭编辑 // 关闭编辑
@@ -406,8 +387,8 @@ export default {
this.player.dispose() this.player.dispose()
} }
this.$emit('close') this.$emit('close')
}, }
}, }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -423,10 +404,12 @@ export default {
max-height: calc(100% - 30px); max-height: calc(100% - 30px);
max-width: calc(100% - 30px); max-width: calc(100% - 30px);
} }
.el-dialog .el-dialog__body { .el-dialog .el-dialog__body {
flex: 1; flex: 1;
overflow: auto; overflow: auto;
} }
.videoBox { .videoBox {
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -436,15 +419,18 @@ export default {
.el-textarea.is-disabled.ti .el-textarea__inner { .el-textarea.is-disabled.ti .el-textarea__inner {
color: red; color: red;
} }
.media-box { .media-box {
width: 100%; width: 100%;
height: 400px; height: 400px;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
img { img {
height: 100%; height: 100%;
max-width: 100%; max-width: 100%;
} }
#my-video { #my-video {
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
@@ -0,0 +1,469 @@
<template>
<el-dialog
:title="title"
:visible.sync="Visible"
width="1800px"
center
class="ac-dialog"
:close-on-click-modal="false"
@close="close">
<el-form :inline="true" :model="form" class="demo-form-inline" label-width="120px" label-position="right">
<div>
<el-form-item label="标题">
<el-input v-model="form.title" style="width: 315px" />
</el-form-item>
</div>
<div>
<el-form-item label="封面">
<UploadImg @changeImgUrl="changeCoverImgUrl" :img="form.coverImg" @onRemove="handleRemove('coverImg')">
</UploadImg>
</el-form-item>
</div>
<el-form-item label="影片类型">
<el-select clearable placeholder="影片类型" v-model="form.type" style="width: 180px">
<el-option label="长视频" value="longvideo" />
<el-option label="短视频" value="shortvideo" />
</el-select>
</el-form-item>
<el-form-item label="视频归类">
<el-select placeholder="请选择视频归类" v-model="videoType" style="width: 180px">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in formVideoTypeList" />
</el-select>
</el-form-item>
<div>
<el-form-item label="APP">
<el-select placeholder="APP" v-model="form.appids" style="width: 180px">
<el-option label="麻豆APP" :value="1" />
<el-option label="麻豆官网" :value="2" />
<el-option label="逼喱逼喱" :value="3" />
</el-select>
</el-form-item>
</div>
<div>
<el-form-item label="上架时间">
<el-date-picker
style="width: 180px"
v-model="form.addedTime"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-ddTHH:mm:ssZ">
</el-date-picker>
</el-form-item>
</div>
<div>
<el-form-item label="正片地址">
<el-input v-model="form.fieldNameFs" style="width: 515px" disabled="disabled" />
</el-form-item>
</div>
<div>
<el-form-item label="预览地址">
<el-input v-model="form.preFileName" style="width: 515px">
<el-button slot="append" @click="innerVisible = true">自定义设置预览</el-button>
</el-input>
</el-form-item>
</div>
<el-form-item label="详细描述">
<el-input v-model="form.desc" type="textarea" style="width: 515px" />
</el-form-item>
</el-form>
<div style="position: absolute; top: 50px; right: 10px">
<h3>正片</h3>
<div v-if="form.fieldNameFs" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer
ref="player"
v-if="form.fieldNameFs.indexOf('mp4') === -1"
:video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.fieldNameFs),
type: 'hls',
pic: ''
}"
hotkey></DPlayer>
<DPlayer
ref="player"
v-else
:video="{
url:
this.$store.getters.getSystemConfig.mp4Url + form.fieldNameFs,
type: 'mp4',
pic: ''
}"
hotkey></DPlayer>
</div>
<UploadVideo
v-if="videoType"
@changeVideoUrl="changeVideoUrl"
:appId="form.appids ? form.appids : 888"
:type="videoType"
@repeatVideo="repeatVideo"
style="max-width: 520px"></UploadVideo>
<div v-else class="check_upload" @click.prevent="checkUpload">
<div>
选择文件
</div>
</div>
</div>
<div style="position: absolute; top: 50px; right: 410px">
<h3>预览</h3>
<div v-if="form.preFileName" style="width: 380px; height: 240px; overflow: hidden">
<DPlayer
ref="player"
v-if="form.preFileName.indexOf('mp4') === -1"
:video="{
url: '/api/web/media/m3u8/' + filterM3u8(form.preFileName),
type: 'hls',
pic: ''
}"
hotkey></DPlayer>
<DPlayer
ref="player"
v-else
:video="{
url:
this.$store.getters.getSystemConfig.mp4Url + form.preFileName,
type: 'mp4',
pic: ''
}"
hotkey></DPlayer>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click.native.prevent="Visible = false"> </el-button>
<el-button type="primary" @click.native.prevent="submit('ruleForm')">
</el-button>
</div>
<el-dialog width="30%" title="设置预览时长" :visible.sync="innerVisible" append-to-body>
<el-row>
<el-col :span="24" style="text-align: center">
<div><span>总时长:</span>{{ totalTime }}s</div>
<div>
:
<el-input-number :min="0" :max="24" size="mini" v-model="previewTimeData.h"></el-input-number>
</div>
<div>
:
<el-input-number :min="0" :max="59" size="mini" v-model="previewTimeData.m"></el-input-number>
</div>
<div>
:
<el-input-number :min="0" :max="59" size="mini" v-model="previewTimeData.s"></el-input-number>
</div>
</el-col>
<el-col :span="24" style="text-align: center; margin: 10px 0">
<el-button-group>
<el-button type="info" @click.native.prevent="restTime">取消</el-button>
<el-button type="primary" @click.native.prevent="subimitPTime">确定
</el-button>
</el-button-group>
</el-col>
</el-row>
</el-dialog>
</el-dialog>
</template>
<script>
import DPlayer from '@/components/VueDplayerHls/index'
import UploadImg from '@/components/UploadImg/index'
import UploadVideo from '@/components/UploadVideoLibraryV2/index'
import 'videojs-contrib-hls'
import { mediaUpdateV2, updatePreTime } from '@/api/mediaLibrary/videoList'
import { stringToArry, arryToString } from '@/filters/index'
import {
StatusList,
formVideoTypeList
} from '@/filters/mediaLibrary/videoList'
import { current } from '@/filters/index'
export default {
name: 'AddOrEdit',
props: ['data'],
components: {
UploadImg,
UploadVideo,
DPlayer
},
computed: {
totalTime() {
return this.data.data.videoTime
}
},
data() {
return {
innerVisible: false,
Visible: true,
title: '',
defaltTime: current() + 'T12:00:00.000Z',
taskId: '',
StatusList: StatusList(),
formVideoTypeList: formVideoTypeList(),
tags: null,
fieldNameFs: '', // 正片地址全称
secondTags: [],
FirstTagList: [],
form: {
appids: undefined,
actors: undefined, // [],演员
addedTime: undefined, // 'string',上架时间
bango: undefined, // 'string',番号
checkSum: undefined, // 'string',md5校验码
country: undefined, // 'string',国家
coverImg: undefined, // 封面
desc: undefined, // 'string',详细描述
directors: undefined, // [],导演
firstTag: undefined, // 'string',一级标签
preFileName: undefined, // 'string',预览文件
preview: undefined, // 0,预览普通视频
publish: undefined, // 'string',视频发布者
secondTags: undefined, // [],二级标签标签
size: undefined, // 0,文件大小
status: undefined, // 'string',当前状态
studio: undefined, // 'string',工作室/所有者
title: undefined, // 'string',标题
type: undefined, // 'string',长视频/短视频
videoTime: undefined // 0,影片长度
},
previewTimeData: {
h: 0,
m: 0,
s: 0
},
type: undefined,
videoType: undefined
}
},
created() {
this.title = this.data.title
if (this.title === '编辑') {
this.form = { ...this.data.data }
this.form.actors = arryToString(this.form.actors)
this.form.directors = arryToString(this.form.directors)
if (this.form.fieldNameFs) {
this.open()
}
}
if (this.player) {
this.player.dispose()
}
},
methods: {
checkUpload() {
if (!this.videoType) {
return this.$message({
type: 'error',
message: '请选择视频归类!!'
})
}
},
// TODO:新增视频时绑定煤资库ID
async subimitPTime() {
let s = 0
if (this.previewTimeData.h) {
s += this.previewTimeData.h * 60 * 60
}
if (this.previewTimeData.m) {
s += this.previewTimeData.m * 60
}
s += this.previewTimeData.s
if (s > 0 && s + 15 <= this.data.data.videoTime - 15) {
const data = {
id: this.data.data.id,
preFileTime: s
}
updatePreTime(data).then(res => {
if (res.code === 200) {
this.$message.success('预览时长设置成功')
this.innerVisible = false
} else {
this.$message.error('预览时长设置失败')
}
})
} else {
this.$message.error('预览时长设置不能为零或不能超过播放时长')
}
},
// TODO:提交视频列表数据
update(data) {
mediaUpdateV2(data).then(res => {
if (res.code === 200) {
this.$message.success('更新成功')
this.close()
} else {
this.$message.error('更新失败')
}
})
},
filterM3u8(v) {
return /\.m3u8/g.test(v) ? v : v + '.m3u8'
},
handleRemove(key) {
this.form[key] = ''
},
// 清空某一项筛选列表
onClear(key) {
this.form.param[key] = []
},
restTime() {
this.previewTimeData = {
h: 0,
m: 0,
s: 0
}
this.innerVisible = false
},
// 提交按钮
submit() {
const data = { ...this.form }
data.appids = data.appids ? [data.appids] : []
data.actors = data.actors ? stringToArry(data.actors) : []
data.directors = data.directors ? stringToArry(data.directors) : []
const YY = new Date().getUTCFullYear()
const MM =
new Date().getMonth() + 1 < 10
? `0${new Date().getMonth() + 1}`
: new Date().getMonth() + 1
const DD =
new Date().getUTCDate() < 10
? `0${new Date().getUTCDate()}`
: new Date().getUTCDate()
const HH =
new Date().getUTCHours() < 10
? `0${new Date().getUTCHours()}`
: new Date().getUTCHours()
const MU =
new Date().getUTCMinutes() < 10
? `0${new Date().getUTCMinutes()}`
: new Date().getUTCMinutes()
const SS =
new Date().getUTCSeconds() < 10
? `0${new Date().getUTCSeconds()}`
: new Date().getUTCSeconds()
const MS =
new Date().getUTCMilliseconds() < 10
? `0${new Date().getUTCMilliseconds()}`
: new Date().getUTCMilliseconds()
data.addedTime =
data.addedTime || `${YY}-${MM}-${DD}T${HH}:${MU}:${SS}.${MS}Z`
this.update(data)
},
// 上传视频返回地址
changeVideoUrl(data) {
console.log(data)
this.form.id = data.id
this.form.fieldNameFs = data.videoUri
this.form.videoTime = parseInt(data.duration)
this.form.size = data.size
},
// 重复上传视频
repeatVideo(data) {
this.taskId = data.taskId
this.getData()
},
// 上传图片返回地址
changeCoverImgUrl(data) {
this.form.coverImg = data
},
// / 监听视频播放的回调函数
onPlayerPlay() { },
// / 监听暂停播放的回调函数
onPlayerPause() { },
// / 监听当前视频数据加载完成
onPlayerLoadeddata() { },
// / 监听当前视频数据加载失败
onPlayerError() { },
// / 监听当前视频数据加载ing
onPlayerWaiting() { },
// / 监听当前视频播放完成
onPlayerEnded() { },
open() {
this.mediaUrl =
'api/web/media/m3u8' +
(this.form.fieldNameFs.match(RegExp(/.m3u8/))
? this.form.fieldNameFs
: this.form.fieldNameFs + '.m3u8')
},
// 关闭编辑
close() {
if (this.player) {
this.player.dispose()
}
this.$emit('close')
}
}
}
</script>
<style lang="scss">
.el-dialog {
display: flex;
flex-direction: column;
margin: 0 !important;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/*height:600px;*/
max-height: calc(100% - 30px);
max-width: calc(100% - 30px);
}
.el-dialog .el-dialog__body {
flex: 1;
overflow: auto;
}
.videoBox {
display: flex;
justify-content: center;
overflow: hidden;
}
.el-textarea.is-disabled.ti .el-textarea__inner {
color: red;
}
.media-box {
width: 100%;
height: 400px;
text-align: center;
overflow: hidden;
img {
height: 100%;
max-width: 100%;
}
#my-video {
width: 100% !important;
height: 100% !important;
border: none !important;
}
}
.check_upload {
position: relative;
padding: 10px;
overflow: hidden;
border: 1px dashed #ccc;
background-color: #f5f5f5;
div {
display: inline-block;
position: relative;
padding: 4px 8px;
font-size: 100%;
line-height: 1.4;
color: #666;
border: 1px solid #666;
cursor: pointer;
border-radius: 2px;
background: none;
outline: none;
}
}
</style>