图片、视频加载方式
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
|
||||
+19
-1
@@ -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>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
@@ -5,17 +11,29 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixinSyscfg from './mixins/mixinSyscfg'
|
||||
|
||||
export default {
|
||||
name: 'App'
|
||||
name: 'App',
|
||||
mixins: [mixinSyscfg],
|
||||
async created() {
|
||||
await this.getSyscfg()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.el-tooltip__popper {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
font-size: 12px !important;
|
||||
color: rgb(56, 51, 51) !important;
|
||||
}
|
||||
|
||||
.tag-wrap {
|
||||
// height: 200px;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
-->
|
||||
<template>
|
||||
<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不好手动触发上传功能 -->
|
||||
<uploader
|
||||
:style="{ display: 'none' }"
|
||||
:options="{ ...options, target: '/api/web/file/uploadImg' }"
|
||||
:style="{ display: 'none' }"
|
||||
:options="{ ...options, target: '/api/web/file/uploadImg' }"
|
||||
class="uploader-example"
|
||||
@file-success="imageSuccess">
|
||||
@file-success="imageSuccess">
|
||||
<uploader-drop>
|
||||
<uploader-btn ref="editorUploadImg" :attrs="attrsImg"></uploader-btn>
|
||||
</uploader-drop>
|
||||
@@ -22,6 +26,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { handleVerAutoImg } from '@/utils/index.js'
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.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 { ImageDrop } from 'quill-image-drop-module'
|
||||
import ImageResize from 'quill-image-resize-module'
|
||||
import { data } from 'qrcode.vue'
|
||||
Quill.register('modules/imageDrop', ImageDrop)
|
||||
Quill.register('modules/imageResize', ImageResize)
|
||||
|
||||
@@ -49,6 +55,7 @@ export default {
|
||||
textNode: {
|
||||
default: ''
|
||||
}
|
||||
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
@@ -69,7 +76,8 @@ export default {
|
||||
const _that = this
|
||||
return {
|
||||
content: '',
|
||||
domain: this.$store.getters.getSystemConfig.webImgReq,
|
||||
imgPath: [],
|
||||
domain: this.$store.getters.getSystemConfig.webImgReq, // 不能暴露源站地址
|
||||
attrsImg: {
|
||||
accept: ['image/*']
|
||||
},
|
||||
@@ -105,7 +113,7 @@ export default {
|
||||
}
|
||||
},
|
||||
// //配置富文本框图片大小调整功能
|
||||
// imageDrop: true,
|
||||
imageDrop: true,
|
||||
imageResize: {
|
||||
displayStyles: {
|
||||
backgroundColor: 'black',
|
||||
@@ -114,6 +122,7 @@ export default {
|
||||
},
|
||||
modules: ['Resize', 'DisplaySize', 'Toolbar']
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,33 +130,67 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
methods: {
|
||||
// 父组件获取数据
|
||||
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) {
|
||||
const data = this.textNode.replace('img src="', 'img src="' + this.domain)
|
||||
e.container.querySelector('.ql-blank').innerHTML = data
|
||||
this.content = this.textNode.replace(/<img\s+([^>]*?)src="([^"]*?)"[^>]*data-custom="([^"]*?)"([^>]*?)>/g, (match, before, srcValue, customValue, after) => {
|
||||
// 互换 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)
|
||||
if (code === 200) {
|
||||
this.storageBase64 = await handleVerAutoImg(this.domain + data.path)
|
||||
|
||||
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
|
||||
// editor方法获取当前光标位置
|
||||
// 获取当前光标位置
|
||||
const imgElement = document.createElement('img')
|
||||
imgElement.src = base64Data
|
||||
// 将 imgElement 插入到编辑器中
|
||||
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)
|
||||
}
|
||||
|
||||
// 读取 Blob 数据
|
||||
reader.readAsDataURL(file.file)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* @LastEditTime: 2020-11-24 17:04:24
|
||||
-->
|
||||
<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-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>
|
||||
<div v-else class="media-box" id="img-box" > <img :src="mediaUrl" /></div>
|
||||
@@ -17,6 +17,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { handleVerAutoImg } from '@/utils/index.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -32,10 +33,14 @@ export default {
|
||||
token() {
|
||||
return this.$store.state.token
|
||||
}
|
||||
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
async changeImg(url) {
|
||||
return await handleVerAutoImg(this.domain + url)
|
||||
},
|
||||
handleClose() {
|
||||
if (this.player) {
|
||||
this.player.dispose()
|
||||
@@ -58,31 +63,26 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.my_data{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.img_dialog{
|
||||
::v-deep{
|
||||
.el-dialog__body{
|
||||
.el-dialog__body{
|
||||
height: auto;
|
||||
.el-carousel__item{
|
||||
overflow: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.media-box {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
img {
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
#my-video {
|
||||
width: 100% !important;
|
||||
@@ -90,4 +90,5 @@ export default {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
<div class="showImg">
|
||||
<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}">
|
||||
<i class="el-icon-loading"></i>加载中
|
||||
</div>
|
||||
@@ -28,6 +28,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import Dialog from './components/dialog'
|
||||
import { handleVerAutoImg } from '@/utils/index.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -43,15 +44,12 @@ export default {
|
||||
},
|
||||
props: ['width', 'height', 'urls'],
|
||||
watch: {
|
||||
urls(newval, oldval) {
|
||||
async urls(newval, oldval) {
|
||||
this.urls = newval
|
||||
// if (this.type && this.type === 'daichong') {
|
||||
// this.domain = ''
|
||||
// }
|
||||
this.imgsUrl = []
|
||||
if (this.urls) { // 判断是否存在
|
||||
if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组
|
||||
this.src = this.domain + this.urls
|
||||
this.src = await handleVerAutoImg(this.domain + this.urls)
|
||||
this.showNoImg = false
|
||||
} else {
|
||||
if (this.urls.length) { // 判断是否为空数组
|
||||
@@ -60,8 +58,8 @@ export default {
|
||||
} else {
|
||||
this.showChangeBtn = true
|
||||
}
|
||||
this.urls.forEach(item => {
|
||||
this.imgsUrl.push(this.domain + item)
|
||||
this.urls.forEach(async item => {
|
||||
this.imgsUrl.push(await handleVerAutoImg(this.domain + this.urls))
|
||||
})
|
||||
this.src = this.imgsUrl[0]
|
||||
this.showNoImg = false
|
||||
@@ -75,11 +73,11 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
async mounted() {
|
||||
this.imgsUrl = []
|
||||
if (this.urls) { // 判断是否存在
|
||||
if (typeof (this.urls) === 'string') { // 判断是单张图片还是数组
|
||||
this.src = this.domain + this.urls
|
||||
this.src = await handleVerAutoImg(this.domain + this.urls)
|
||||
} else {
|
||||
if (this.urls.length) { // 判断是否为空数组
|
||||
if (this.urls.length === 1) { // 判断数组中是否只有一张图片
|
||||
@@ -87,8 +85,8 @@ export default {
|
||||
} else {
|
||||
this.showChangeBtn = true
|
||||
}
|
||||
this.urls.forEach(item => {
|
||||
this.imgsUrl.push(this.domain + item)
|
||||
this.urls.forEach(async item => {
|
||||
this.imgsUrl.push(await handleVerAutoImg(this.domain + item))
|
||||
})
|
||||
this.src = this.imgsUrl[0]
|
||||
} else {
|
||||
@@ -118,12 +116,12 @@ export default {
|
||||
}
|
||||
},
|
||||
// 查看媒体
|
||||
checkMedia() {
|
||||
async checkMedia() {
|
||||
if (this.urls) { // 判断是否存在
|
||||
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 {
|
||||
this.$refs.dialog.open(this.urls, 'img')
|
||||
this.$refs.dialog.open(this.imgsUrl, 'img')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
<span>视频时长:{{ this.myData.playTime + "s" }}</span>
|
||||
</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
|
||||
ref="player"
|
||||
:video="{
|
||||
url: mediaUrl,
|
||||
type: type === 'mp4' ? '' : 'hls',
|
||||
type: type=== 'mp4' ?'':'hls',
|
||||
pic: '',
|
||||
}"
|
||||
hotkey
|
||||
@@ -53,7 +53,7 @@ export default {
|
||||
title: '封面图查看',
|
||||
params: {},
|
||||
myData: {},
|
||||
type: undefined,
|
||||
type: undefined,
|
||||
domain: '/api/web/media/m3u8/' // 存放图片的域名
|
||||
}
|
||||
},
|
||||
@@ -79,6 +79,7 @@ export default {
|
||||
// 视频审查列表
|
||||
videoFeviewList() {
|
||||
videoFeviewList(this.params, this.id).then((res) => {
|
||||
|
||||
// this.myData = res.data,
|
||||
})
|
||||
},
|
||||
@@ -93,18 +94,35 @@ export default {
|
||||
this.myData = { ...data }
|
||||
this.dialogVisible = true
|
||||
this.title = '视频查看'
|
||||
this.mediaUrl =
|
||||
this.domain + (url.match(RegExp(/.m3u8/)) ? url : url + '.m3u8')
|
||||
if (url.indexOf('mp4') !== -1) {
|
||||
this.mediaUrl = this.$store.getters.getSystemConfig.webImgReq + url
|
||||
if (url.indexOf('mp4') !== -1) {
|
||||
this.mediaUrl = this.$store.getters.getSystemConfig.mp4Url + url
|
||||
this.type = 'mp4'
|
||||
} else {
|
||||
this.mediaUrl =
|
||||
this.domain + (url.match(RegExp(/.m3u8/)) ? url : url + '.m3u8')
|
||||
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);
|
||||
// });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,28 +2,35 @@
|
||||
* @Author: 王涛
|
||||
* @Mail: no
|
||||
* @Date: 2020-09-29 19:56:44
|
||||
* @LastEditors: Please set LastEditors
|
||||
* @LastEditTime: 2022-06-21 20:05:54
|
||||
* @LastEditors: Administrator admin@example.com
|
||||
* @LastEditTime: 2024-11-19 10:14:08
|
||||
-->
|
||||
<template>
|
||||
<!-- 使用方法 <UploadImg @changeImgUrl='changeMobileAvatar' :img='form.mobileAvatar' :width='"100px"' :height='"100px"'></UploadImg>
|
||||
changeMobileAvatar(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">
|
||||
<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-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</div>
|
||||
</el-upload>
|
||||
</template>
|
||||
<script>
|
||||
import { handleVerAutoImg } from '@/utils/index.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
domain: this.$store.getters.getSystemConfig.webImgReq,
|
||||
imageUrl: ''
|
||||
imageUrl: '',
|
||||
newImg: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@@ -38,11 +45,23 @@ export default {
|
||||
height: {
|
||||
type: String,
|
||||
default: '180px'
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
showIndex: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
img: function(val, oldval) {
|
||||
this.imageUrl = val
|
||||
},
|
||||
imageUrl: async function(val, oldval) {
|
||||
const a = await handleVerAutoImg(this.domain + val)
|
||||
this.newImg = a
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -56,6 +75,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async changeImg(url) {
|
||||
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
if (res.code === 200) {
|
||||
this.$message({
|
||||
@@ -74,11 +96,19 @@ export default {
|
||||
}
|
||||
},
|
||||
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) {
|
||||
this.imageUrl = ''
|
||||
this.$emit('onRemove', f)
|
||||
if (this.showIndex) {
|
||||
this.$emit('onRemove', { key: f, index: this.index })
|
||||
} else {
|
||||
this.$emit('onRemove', f)
|
||||
}
|
||||
},
|
||||
// 上传前进行压缩
|
||||
beforeAvatarUpload(file) {
|
||||
@@ -100,7 +130,7 @@ export default {
|
||||
// message: '上传图片大小不能超过 2MB!!'
|
||||
// })
|
||||
// }
|
||||
return isJPG
|
||||
return isJPG
|
||||
},
|
||||
|
||||
// 图片等比压缩
|
||||
@@ -142,19 +172,21 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409eff;
|
||||
.avatar-uploader {
|
||||
.el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.el-upload:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
color: #d9d9d9;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 100%;
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
<div>
|
||||
<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;">
|
||||
<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="#">
|
||||
<div class="image-mask">
|
||||
<span class="add" @click="handlePictureCardPreview(domain+img)">
|
||||
<span class="add" @click="handlePictureCardPreview(imgSrc[index])">
|
||||
<i class="el-icon-view"></i>
|
||||
</span>
|
||||
<span class="delete" @click="removeImage(index)">
|
||||
@@ -33,6 +33,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import { handleVerAutoImg } from '@/utils/index.js'
|
||||
export default {
|
||||
components: { draggable },
|
||||
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' }
|
||||
],
|
||||
drag: false, // 拖拽效果是否开启
|
||||
locaImg: []
|
||||
locaImg: [],
|
||||
imgSrc: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@@ -57,6 +59,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
dragOptions() {
|
||||
return {
|
||||
@@ -66,6 +69,7 @@ export default {
|
||||
ghostClass: 'ghost'
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
// 监听拖动事件改变时,传出新的图片数组
|
||||
@@ -80,15 +84,23 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
async mounted() {
|
||||
this.locaImg = []
|
||||
if (this.img) {
|
||||
this.img.filter((item) => {
|
||||
this.locaImg.push(item)
|
||||
})
|
||||
}
|
||||
// 在组件挂载时加载图像 URL
|
||||
this.imgSrc = await Promise.all(this.locaImg.map(img => this.changeImg(img)))
|
||||
},
|
||||
methods: {
|
||||
async changeImg(img) {
|
||||
// 这里应该替换为真实的异步代码
|
||||
const a = await handleVerAutoImg(this.domain + img)
|
||||
return a
|
||||
},
|
||||
|
||||
handleChange(file, fileList) {
|
||||
if (file.status === 'success') {
|
||||
this.locaImg.push(file.response.data.path)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<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 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>
|
||||
@@ -18,6 +18,8 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mediaUploadImg } from '@/api/components/UploadImgPaste'
|
||||
import { handleVerAutoImg } from '@/utils/index.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -34,6 +36,10 @@ export default {
|
||||
watch: {
|
||||
img: function(val) {
|
||||
this.imageUrl = val
|
||||
},
|
||||
imageUrl: async function(val, oldval) {
|
||||
const a = await handleVerAutoImg(this.domain + val)
|
||||
this.newImg = a
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -44,6 +50,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
handleDrag(event) {
|
||||
const items = Array.from(event.dataTransfer.items)
|
||||
let file = null
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
* @Author: 王涛
|
||||
* @Mail: no
|
||||
* @Date: 2020-10-10 14:27:58
|
||||
* @LastEditors: Please set LastEditors
|
||||
* @LastEditTime: 2022-03-14 15:29:54
|
||||
* @LastEditors: 江涛
|
||||
* @LastEditTime: 2021-03-24 19:34:23
|
||||
*/
|
||||
const state = {
|
||||
config: {
|
||||
@@ -15,7 +15,7 @@ const state = {
|
||||
driverGroup: undefined, // 开车群
|
||||
headerM3U8: undefined, // 片头m3u8
|
||||
id: 0,
|
||||
webImgReq: 'http://resourceyuan.bbaazz.me/', // 图片请求域名(web使用)
|
||||
webImgReq: '', // 图片请求域名(web使用)
|
||||
imgReq: undefined, // 图片请求域名(app使用)
|
||||
imgUpload: undefined, // 图片上传地址
|
||||
inviteAddr: undefined, // 用户邀请地址
|
||||
|
||||
@@ -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
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Created by PanJiaChen on 16/11/18.
|
||||
*/
|
||||
|
||||
import { decryptImage } from './imgCode.js'
|
||||
/**
|
||||
* Parse the time to string
|
||||
* @param {(Object|string|number)} time
|
||||
@@ -227,3 +227,88 @@ export function getQueryString(name) {
|
||||
}
|
||||
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>
|
||||
<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">
|
||||
<el-row :gutter="24">
|
||||
<el-col >
|
||||
<h3>AI生成的视频URl</h3>
|
||||
<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),
|
||||
type: 'hls',
|
||||
pic: '',
|
||||
}" hotkey ></DPlayer>
|
||||
<DPlayer ref="player" v-else :video="{
|
||||
url: this.$store.getters.getSystemConfig.webImgReq + form.vidUrl,
|
||||
}"
|
||||
hotkey ></DPlayer>
|
||||
<DPlayer
|
||||
ref="player"
|
||||
v-else
|
||||
:video="{
|
||||
url: this.$store.getters.getSystemConfig.mp4Url + form.vidUrl,
|
||||
type: 'mp4',
|
||||
pic: '',
|
||||
}" hotkey ></DPlayer>
|
||||
}"
|
||||
hotkey ></DPlayer>
|
||||
</div>
|
||||
|
||||
|
||||
</el-col>
|
||||
</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">
|
||||
<el-row :gutter="24">
|
||||
<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
|
||||
@@ -43,8 +63,7 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="Visible = false"> 取 消 </el-button>
|
||||
<el-button type="primary" @click="submit('form')"> 确 定 </el-button>
|
||||
@@ -76,15 +95,15 @@ export default {
|
||||
formData: {},
|
||||
// 表单数据
|
||||
form: {
|
||||
"byWay": undefined,
|
||||
"id": undefined,
|
||||
"modifyImgs": undefined,
|
||||
"vidUrl": undefined,
|
||||
"reason": undefined,
|
||||
"status": 0,
|
||||
"updatedAt": undefined
|
||||
'byWay': undefined,
|
||||
'id': undefined,
|
||||
'modifyImgs': undefined,
|
||||
'vidUrl': undefined,
|
||||
'reason': undefined,
|
||||
'status': 0,
|
||||
'updatedAt': undefined
|
||||
},
|
||||
rules: {},
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -95,22 +114,20 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//TODO:新增应用列表数据
|
||||
|
||||
filterM3u8(v) {
|
||||
// TODO:新增应用列表数据
|
||||
|
||||
filterM3u8(v) {
|
||||
return /\.m3u8/g.test(v) ? v : v + '.m3u8'
|
||||
},
|
||||
//TODO:编辑应用列表数据
|
||||
// TODO:编辑应用列表数据
|
||||
update(data) {
|
||||
|
||||
aiorderFacechangeUpdate(data).then((res) => {
|
||||
if (res && res.code === 200) {
|
||||
this.$message.success(res.data ? res.data : '更新成功')
|
||||
} 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) {
|
||||
this.form.modifyImgs = data
|
||||
},
|
||||
|
||||
|
||||
// 关闭编辑
|
||||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
|
||||
|
||||
onClear(data) {
|
||||
this.form[data] = undefined
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,26 +1,46 @@
|
||||
<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">
|
||||
<el-row :gutter="24">
|
||||
<el-col>
|
||||
<h3>AI生成的视频URl</h3>
|
||||
<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),
|
||||
type: 'hls',
|
||||
pic: '',
|
||||
}" hotkey ></DPlayer>
|
||||
<DPlayer ref="player" v-else :video="{
|
||||
url: this.$store.getters.getSystemConfig.webImgReq + form.modifyVideoUrl,
|
||||
}"
|
||||
hotkey ></DPlayer>
|
||||
<DPlayer
|
||||
ref="player"
|
||||
v-else
|
||||
:video="{
|
||||
url: this.$store.getters.getSystemConfig.mp4Url + form.modifyVideoUrl,
|
||||
type: 'mp4',
|
||||
pic: '',
|
||||
}" hotkey ></DPlayer>
|
||||
}"
|
||||
hotkey ></DPlayer>
|
||||
</div>
|
||||
|
||||
|
||||
</el-col>
|
||||
</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">
|
||||
<el-row :gutter="24">
|
||||
<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-form-item label="换脸方式">
|
||||
<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" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -51,7 +74,6 @@
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="Visible = false"> 取 消 </el-button>
|
||||
<el-button type="primary" @click="submit('form')"> 确 定 </el-button>
|
||||
@@ -83,15 +105,15 @@ export default {
|
||||
formData: {},
|
||||
// 表单数据
|
||||
form: {
|
||||
"byWay": undefined,
|
||||
"id": undefined,
|
||||
"modifyImgs": undefined,
|
||||
"modifyVideoUrl": undefined,
|
||||
"reason": undefined,
|
||||
"status": 0,
|
||||
"updatedAt": undefined
|
||||
'byWay': undefined,
|
||||
'id': undefined,
|
||||
'modifyImgs': undefined,
|
||||
'modifyVideoUrl': undefined,
|
||||
'reason': undefined,
|
||||
'status': 0,
|
||||
'updatedAt': undefined
|
||||
},
|
||||
rules: {},
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -102,18 +124,15 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//TODO:新增应用列表数据
|
||||
// TODO:新增应用列表数据
|
||||
|
||||
filterM3u8(v) {
|
||||
return /\.m3u8/g.test(v) ? v : v + '.m3u8'
|
||||
},
|
||||
//TODO:编辑应用列表数据
|
||||
// TODO:编辑应用列表数据
|
||||
update(data) {
|
||||
|
||||
aiorderStripUpdate(data).then((res) => {
|
||||
|
||||
|
||||
if (res && res.code === 200) {
|
||||
if (res && res.code === 200) {
|
||||
this.$message.success(res.data ? res.data : '更新成功')
|
||||
} else {
|
||||
this.$message.error(res.data ? res.data : '更新失败')
|
||||
@@ -161,8 +180,8 @@ export default {
|
||||
|
||||
onClear(data) {
|
||||
this.form[data] = undefined
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,159 +1,129 @@
|
||||
<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-row :gutter="24">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form-item label="标题">
|
||||
<el-input v-model="form.title" style="width: 315px" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form-item label="封面类型">
|
||||
<el-select style="width: 180px" placeholder="请选择封面类型" v-model="form.coverType">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in coverTypeList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form-item label="视频归类">
|
||||
<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>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<el-form-item label="封面">
|
||||
<UploadImg @changeImgUrl="changeCoverImgUrl" :img="form.coverImg"></UploadImg>
|
||||
</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.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>
|
||||
<el-form-item label="APP">
|
||||
<el-select multiple 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 style="float:left">
|
||||
<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.webImgReq + form.fieldNameFs,
|
||||
<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" :type="videoType" @repeatVideo="repeatVideo"
|
||||
}"
|
||||
hotkey></DPlayer>
|
||||
</div>
|
||||
<UploadVideo
|
||||
v-if="videoType"
|
||||
@changeVideoUrl="changeVideoUrl"
|
||||
:type="videoType"
|
||||
@repeatVideo="repeatVideo"
|
||||
style="max-width: 520px"></UploadVideo>
|
||||
<div v-else class="check_upload" @click.prevent="checkUpload">
|
||||
<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 slot="footer" class="dialog-footer">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
分:
|
||||
<el-input-number :min="0" :max="59" size="mini" v-model="previewTimeData.m"></el-input-number>
|
||||
@@ -193,68 +162,68 @@
|
||||
<script>
|
||||
import DPlayer from '@/components/VueDplayerHls/index'
|
||||
import UploadImg from '@/components/UploadImg/index'
|
||||
import UploadVideo from '@/components/UploadVideoLibrary/index'
|
||||
import UploadVideo from '@/components/UploadVideo/index'
|
||||
import 'videojs-contrib-hls'
|
||||
import { mediaUpdate, updatePreTime } from '@/api/mediaLibrary/videoList'
|
||||
import { stringToArry, arryToString, current } from '@/filters/index'
|
||||
import {
|
||||
coverTypeList,
|
||||
appidsList,
|
||||
formatTypeList,
|
||||
formVideoTypeList
|
||||
} from '@/filters/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','contentTypeList'],
|
||||
props: ['data'],
|
||||
components: {
|
||||
UploadImg,
|
||||
UploadVideo,
|
||||
DPlayer,
|
||||
DPlayer
|
||||
},
|
||||
computed: {
|
||||
totalTime() {
|
||||
return this.data.data.videoTime
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
coverTypeList: coverTypeList(),
|
||||
appidsList: appidsList(),
|
||||
formatTypeList: formatTypeList(),
|
||||
formVideoTypeList: formVideoTypeList(),
|
||||
type: undefined,
|
||||
videoType: undefined,
|
||||
innerVisible: false,
|
||||
Visible: true,
|
||||
title: '',
|
||||
defaltTime: current() + 'T12:00:00.000Z',
|
||||
taskId: '',
|
||||
StatusList: StatusList(),
|
||||
formVideoTypeList: formVideoTypeList(),
|
||||
tags: null,
|
||||
fieldNameFs: '', // 正片地址全称
|
||||
form: {
|
||||
formatType: undefined, // 视频类型 1:长视频 2:短视频 3:预览
|
||||
mediaSet: undefined, // 视频归属
|
||||
contentType: undefined, // 内容类型 1:av(日本) 2:国产(短视频) 3:动漫
|
||||
coverType: undefined, // 封面类型 1:竖版 2:横版 3:系统
|
||||
secondTags: [],
|
||||
FirstTagList: [],
|
||||
|
||||
title: undefined, // 'string',标题
|
||||
addedTime: undefined, // 'string',上架时间
|
||||
publish: undefined, // 'string',视频发布者
|
||||
firstTag: undefined, // 'string',一级标签
|
||||
secondTags: undefined, // [],二级标签标签
|
||||
bango: undefined, // 'string',番号
|
||||
form: {
|
||||
appids: [],
|
||||
desc: undefined, // 'string',详细描述
|
||||
preFileName: undefined, // 'string',预览文件
|
||||
coverImg: 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,
|
||||
s: 0
|
||||
},
|
||||
type: undefined,
|
||||
videoType: undefined
|
||||
}
|
||||
},
|
||||
|
||||
@@ -263,8 +232,7 @@ export default {
|
||||
if (this.title === '编辑') {
|
||||
this.form = { ...this.data.data }
|
||||
this.form.actors = arryToString(this.form.actors)
|
||||
this.form.secondTags = arryToString(this.form.secondTags)
|
||||
this.form.mediaSet = arryToString(this.form.mediaSet)
|
||||
this.form.directors = arryToString(this.form.directors)
|
||||
if (this.form.fieldNameFs) {
|
||||
this.open()
|
||||
}
|
||||
@@ -273,16 +241,44 @@ export default {
|
||||
this.player.dispose()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkUpload() {
|
||||
if (!this.type) {
|
||||
checkUpload() {
|
||||
if (!this.videoType) {
|
||||
return this.$message({
|
||||
type: 'error',
|
||||
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) {
|
||||
mediaUpdate(data).then((res) => {
|
||||
if (res.code === 200) {
|
||||
@@ -296,6 +292,9 @@ export default {
|
||||
filterM3u8(v) {
|
||||
return /\.m3u8/g.test(v) ? v : v + '.m3u8'
|
||||
},
|
||||
handleRemove(key) {
|
||||
this.form[key] = ''
|
||||
},
|
||||
// 清空某一项筛选列表
|
||||
onClear(key) {
|
||||
this.form.param[key] = []
|
||||
@@ -304,57 +303,52 @@ export default {
|
||||
this.previewTimeData = {
|
||||
h: 0,
|
||||
m: 0,
|
||||
s: 0,
|
||||
s: 0
|
||||
}
|
||||
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() {
|
||||
const data = { ...this.form }
|
||||
data.actors = data.actors ? stringToArry(data.actors) : []
|
||||
data.secondTags = data.secondTags ? stringToArry(data.secondTags) : []
|
||||
data.mediaSet = data.mediaSet ? stringToArry(data.mediaSet) : []
|
||||
data.addedTime = data.addedTime
|
||||
? data.addedTime === '0001-01-01T00:00:00Z'
|
||||
? this.defaltTime
|
||||
: data.addedTime
|
||||
: this.defaltTime
|
||||
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) {
|
||||
this.form.id = data.id
|
||||
// this.$set(this.form, 'fieldNameFs', data.videoUri)
|
||||
this.fieldNameFs = data.videoUri
|
||||
// this.form.fieldNameFs = data.videoUri
|
||||
// this.form.videoTime = parseInt(data.duration)
|
||||
// this.form.size = data.size
|
||||
// this.open()
|
||||
this.form.videoTime = parseInt(data.duration)
|
||||
this.form.size = data.size
|
||||
},
|
||||
|
||||
// 重复上传视频
|
||||
@@ -368,36 +362,23 @@ export default {
|
||||
this.form.coverImg = data
|
||||
},
|
||||
// / 监听视频播放的回调函数
|
||||
onPlayerPlay() {},
|
||||
onPlayerPlay() { },
|
||||
// / 监听暂停播放的回调函数
|
||||
onPlayerPause() {},
|
||||
onPlayerPause() { },
|
||||
// / 监听当前视频数据加载完成
|
||||
onPlayerLoadeddata() {},
|
||||
onPlayerLoadeddata() { },
|
||||
// / 监听当前视频数据加载失败
|
||||
onPlayerError() {},
|
||||
onPlayerError() { },
|
||||
// / 监听当前视频数据加载ing
|
||||
onPlayerWaiting() {},
|
||||
onPlayerWaiting() { },
|
||||
// / 监听当前视频播放完成
|
||||
onPlayerEnded() {},
|
||||
onPlayerEnded() { },
|
||||
open() {
|
||||
this.mediaUrl =
|
||||
'api/web/media/m3u8/' +
|
||||
'api/web/media/m3u8' +
|
||||
(this.form.fieldNameFs.match(RegExp(/.m3u8/))
|
||||
? this.form.fieldNameFs
|
||||
: 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.$emit('close')
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@@ -423,10 +404,12 @@ export default {
|
||||
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;
|
||||
@@ -436,15 +419,18 @@ export default {
|
||||
.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;
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user