<template>
|
<div>
|
<Card>
|
<Form
|
ref="searchForm"
|
@keydown.enter.native="handleSearch"
|
:model="searchForm"
|
inline
|
:label-width="70"
|
class="search-form"
|
>
|
<Form-item label="标题" prop="title">
|
<Input
|
type="text"
|
v-model="searchForm.title"
|
clearable
|
@on-clear="handleSearch"
|
@on-change="handleSearch"
|
style="width: 160px"
|
/>
|
</Form-item>
|
<Form-item label="标签" prop="tagList">
|
<Select
|
v-model="searchForm.tagList"
|
clearable
|
filterable
|
multiple
|
@on-clear="handleSearch"
|
@on-change="handleSearch"
|
style="width: 160px"
|
>
|
<Option v-for="tag in tagList" :key="tag.id" :value="tag.id">{{ tag.tagName }}</Option>
|
</Select>
|
</Form-item>
|
<Form-item label="视频状态" prop="status">
|
<Select
|
v-model="searchForm.status"
|
clearable
|
@on-clear="handleSearch"
|
@on-change="handleSearch"
|
style="width: 160px"
|
>
|
<Option value="99">待审核</Option>
|
<Option value="1">已发布</Option>
|
<Option value="0">已下架</Option>
|
<Option value="-1">审核未通过</Option>
|
</Select>
|
</Form-item>
|
<Button
|
@click="handleSearch"
|
type="primary"
|
icon="ios-search"
|
class="search-btn"
|
>搜索
|
</Button
|
>
|
</Form>
|
|
<Row class="operation padding-row">
|
<Button @click="recreateEsIndex" type="primary">重新构建es索引</Button>
|
<Button @click="openUploadVideo" type="primary" icon="md-arrow-up"> 上传视频</Button>
|
</Row>
|
|
<Modal
|
v-model="upLoadVideoShow"
|
:title="uploadVideoForm.id?'编辑主页视频':'上传主页视频'"
|
width="800"
|
:mask-closable="false"
|
>
|
<Form
|
ref="searchForm"
|
@keydown.enter.native="handleSearch"
|
:model="uploadVideoForm"
|
inline
|
>
|
<Row :gutter="24" class="operation padding-row" style="width: 100%;">
|
<Col span="12">
|
<FormItem label="标题:" :label-width="80">
|
<Input v-model="uploadVideoForm.title" placeholder="请输入标题"></Input>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="上传类型:" :label-width="80" prpo="videoContentType">
|
<Select v-model="uploadVideoForm.videoContentType" style="width:200px">
|
<Option value="img">图片</Option>
|
<Option value="video">视频</Option>
|
</Select>
|
</FormItem>
|
</Col>
|
</Row>
|
<Row>
|
<Col span="12" v-if="!uploadVideoForm.videoFileKey&&showVideoFlag">
|
<FormItem :label-width="80" label="上传视频" prop="videoFileKey">
|
<Upload
|
:multiple="true"
|
:before-upload="upLoadVideo"
|
accept="video/*"
|
action=""
|
>
|
<Button icon="ios-cloud-upload-outline">选择视频</Button>
|
</Upload>
|
<Progress :percent="videoProgress" v-if="showVideoProgress" status="active"/>
|
</FormItem>
|
</Col>
|
<Col span="12" v-else-if="uploadVideoForm.videoFileKey">
|
<FormItem :labelWidth="80" label="视频">
|
<video style="width: 150px;height: 150px"
|
controls
|
@loadedmetadata="getVideoDuration"
|
:poster="uploadVideoForm.showCoverUrl"
|
:autoplay="false"
|
id="remoteVideo" :src="uploadVideoForm.showVideoUrl"
|
ref="videoInfo"
|
></video>
|
</FormItem>
|
</Col>
|
</Row>
|
<Row :gutter="24">
|
<Col span="12" v-if="uploadVideoForm.videoFileKey">
|
<FormItem :labelWidth="80">
|
<Button @click="reloadVideo" type="primary">重新上传视频</Button>
|
</FormItem>
|
</Col>
|
</Row>
|
<Row :gutter="24" v-if="uploadVideoForm.videoImgs&&showImgFlag">
|
<Col span="12">
|
<FormItem :labelWidth="80" label="上传图片">
|
<template>
|
<div class="demo-upload-list" v-for="item in uploadVideoForm.showListImages" :key="item">
|
<template>
|
<img :src="item">
|
<div class="demo-upload-list-cover">
|
<Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon>
|
<Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
|
</div>
|
</template>
|
<!-- <template v-else>-->
|
<!-- <Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>-->
|
<!-- </template>-->
|
</div>
|
<Upload
|
ref="upload"
|
:show-upload-list="false"
|
:format="['jpg','jpeg','png']"
|
:max-size="2048"
|
:before-upload="upLoadImg"
|
multiple
|
type="drag"
|
action="-"
|
style="display: inline-block;width:58px;">
|
<div style="width: 58px;height:58px;line-height: 58px;">
|
<Icon type="ios-camera" size="20"></Icon>
|
</div>
|
</Upload>
|
<Modal title="图片预览" v-model="visible">
|
<img :src="imgName" v-if="visible" style="width: 100%">
|
</Modal>
|
</template>
|
</FormItem>
|
</Col>
|
</Row>
|
<Row :gutter="24">
|
<Col span="24">
|
<FormItem label="标签" :label-width="80" style="width: 100%">
|
<Select v-model="chooseTag" filterable multiple allow-create @on-create="createVideoTag">
|
<Option v-for="item in videoTagList" :value="item.tagName" :key="item.id">{{ item.tagName }}</Option>
|
</Select>
|
</FormItem>
|
</Col>
|
</Row>
|
<Row :gutter="24">
|
<Col span="24">
|
<FormItem label="选中商品" :label-width="80">
|
</FormItem>
|
</Col>
|
</Row>
|
<Row :gutter="24">
|
<Col span="12">
|
<FormItem label="商品列表" :label-width="80">
|
<Input v-model="searchGoodsForm.keyword" style="width:200px" @on-change="searchGoodsList"></Input>
|
<div style="height: 400px;overflow: auto;">
|
<div v-for="item in goodsData" :key="item.id" style="display: flex;
|
align-items: center;justify-content: flex-start;border: 1px solid gray;margin-top: 10px;
|
padding: 10px;border-radius: 20px" @click="chooseGoods(item.id)">
|
<div>
|
<img :src="endpoint+'/'+item.thumbnail" style="width: 80px;height: 80px">
|
</div>
|
<div style="display: flex;flex-direction: column;margin-left: 20px">
|
<div style="font-size: 1.5em;font-weight: bold">{{ item.goodsName }}</div>
|
<div style="color: #ff6f6f">
|
¥{{ item.price }}
|
</div>
|
</div>
|
</div>
|
</div>
|
<Page
|
:current="searchGoodsForm.pageNumber"
|
:total="goodsTotal"
|
:page-size="searchGoodsForm.pageSize"
|
@on-change="goodsChangePage"
|
@on-page-size-change="goodsChangePageSize"
|
:page-size-opts="[10, 20, 50]"
|
size="small"
|
show-total
|
show-elevator
|
show-sizer
|
></Page>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="选中商品" :label-width="80">
|
<div style="height: 400px;overflow: auto;">
|
<div v-for="(item,index) in uploadVideoForm.goodsList" :key="item.id" style="display: flex;
|
align-items: center;justify-content: flex-start;border: 1px solid gray;margin-top: 10px;
|
padding: 10px;border-radius: 20px">
|
<div>
|
<img :src="endpoint+'/'+item.thumbnail" style="width: 80px;height: 80px">
|
</div>
|
<div style="display: flex;flex-direction: column;margin-left: 20px">
|
<div style="font-size: 1.5em;font-weight: bold">{{ item.goodsName }}</div>
|
<div style="color: #ff6f6f;display: flex;align-content: center;justify-content: flex-start">
|
<div> ¥{{ item.price }}</div>
|
<div style="margin-left: 10px">
|
<InputNumber v-model="item.goodsNum" :min="0" :max="99" controls-outside @on-change="changeGoodsNum(item.goodsSkuId,index,item.goodsNum)"
|
style="vertical-align: center;width: 100px"></InputNumber>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</FormItem>
|
</Col>
|
|
</Row>
|
|
</Form>
|
<div slot="footer">
|
<Button type="text" @click="closeVideoUpload">关闭</Button>
|
<Button type="primary" @click="submitVideoUpload">确认</Button>
|
</div>
|
</Modal>
|
<Modal
|
v-model="playVideoShow"
|
:title="playVideoTitle"
|
width="800"
|
:mask-closable="false"
|
@close="playVideoClose"
|
>
|
<div class="video-warp">
|
<video :src="playVideoUrl" autoplay controls style="width: 768px;height: 432px"/>
|
</div>
|
<div slot="footer">
|
<Button type="text" @click="playVideoClose">关闭</Button>
|
</div>
|
</Modal>
|
|
<Modal
|
v-model="auditingShow"
|
title="视频审核"
|
width="1200"
|
:loading="auditingLoading"
|
:mask-closable="false"
|
>
|
<Form
|
ref="auditingForm"
|
:model="auditingForm"
|
:label-width="70"
|
:rules="auditingRule"
|
>
|
<Form-item label="标题:">
|
<div>{{ detail.title }}</div>
|
</Form-item>
|
<Form-item label="标签:">
|
<div style="display: flex;flex-wrap: wrap">
|
<div v-for="(tag, index) in detail.tagList" :key="'tag' + index" style="margin-right: 5px">
|
<Tag color="red">{{ tag.tagName }}</Tag>
|
</div>
|
</div>
|
</Form-item>
|
<Form-item v-if="detail.videoContentType === 'video'" label="视频时长:" :label-width="72">
|
<div>{{ formatSeconds(detail.videoDuration) }}</div>
|
</Form-item>
|
<Form-item v-if="detail.videoContentType === 'img'" label="图片张数:" :label-width="72">
|
<div>{{ detail.imgs.length }}</div>
|
</Form-item>
|
<Form-item v-if="detail.videoContentType === 'video'" class="video-warp" :label-width="0">
|
<Row>
|
<Col span="11">
|
<video :src="detail.videoUrl" autoplay controls style="width: 500px;height: 300px"/>
|
</Col>
|
<Col span="13" style="max-height: 300px;overflow-y: scroll">
|
<Row v-for="goods in detail.goodsList" :key="goods.goodsId" style="width: 100%">
|
<Row style="width:100%;align-items: center">
|
<Col span="6">
|
<img :src="goods.thumbnail" style="width: 100px;height: 100px"/>
|
</Col>
|
<Col span="10">
|
<p>商品名称: {{ goods.goodsName }}</p>
|
</Col>
|
<Col span="4">
|
<p>商品单价: ¥{{ goods.price }}</p>
|
</Col>
|
<Col span="4">
|
<p>商品数量: {{ goods.goodsNum }}</p>
|
</Col>
|
</Row>
|
</Row>
|
</Col>
|
</Row>
|
|
</Form-item>
|
<Form-item v-if="detail.videoContentType === 'img'" :label-width="0">
|
<div style="display: flex;flex-direction: row;flex-wrap: wrap">
|
<div v-for="img in detail.imgs" :key="img" class="img-warp">
|
<img :src="img" class="image">
|
</div>
|
<Row v-for="goods in detail.goodsList" :key="goods.goodsId" style="width: 100%">
|
<Row style="width:100%;align-items: center; padding: 5px 10px">
|
<Col span="6">
|
<img :src="goods.thumbnail" style="width: 100px;height: 100px"/>
|
</Col>
|
<Col span="10">
|
<p>商品名称: {{ goods.goodsName }}</p>
|
</Col>
|
<Col span="4">
|
<p>商品单价: ¥{{ goods.price }}</p>
|
</Col>
|
<Col span="4">
|
<p>商品数量: {{ goods.goodsNum }}</p>
|
</Col>
|
</Row>
|
</Row>
|
</div>
|
|
</Form-item>
|
<Form-item label="审核结果:" :label-width="100" prop="result">
|
<RadioGroup v-model="auditingForm.result">
|
<Radio :label="1">通过</Radio>
|
<Radio :label="0">不通过</Radio>
|
</RadioGroup>
|
</Form-item>
|
<Form-item v-show="auditingForm.result === 0" label="不通过原因:" :label-width="100" prop="reason">
|
<Input
|
type="textarea"
|
v-model="auditingForm.reason"
|
clearable
|
style="width: 100%"
|
/>
|
</Form-item>
|
</Form>
|
<div slot="footer">
|
<Button type="text" @click="closeAuditing">关闭</Button>
|
<Button type="primary" @click="submitAuditing">确认</Button>
|
</div>
|
</Modal>
|
|
<Modal
|
v-model="videoDownShow"
|
title="视频下架"
|
width="800"
|
:mask-closable="false"
|
>
|
<Form :model="videoDownForm" :rules="videoDownRule" ref="videoDownForm">
|
<FormItem label="下架原因:" :labelWidth="100" prop="reason">
|
<editor ref="editor" @input="getReason"/>
|
</FormItem>
|
</Form>
|
<div slot="footer">
|
<Button type="text" @click="closeVideoDown">关闭</Button>
|
<Button type="primary" @click="videoDown">确认</Button>
|
</div>
|
</Modal>
|
|
<Table
|
:loading="loading"
|
border
|
:columns="columns"
|
:data="data"
|
ref="table"
|
sortable="custom"
|
@on-sort-change="changeSort"
|
@on-selection-change="showSelect"
|
>
|
<template slot-scope="{ row, index }" slot="tagList">
|
<div v-for="(tag, index) in row.tagList" :key="'tag' + index" style="margin-top: 5px">
|
<Tag color="red">{{ tag.tagName }}</Tag>
|
</div>
|
</template>
|
<template slot-scope="{ row, index }" slot="videoFileKey">
|
<div v-if="row.videoContentType === 'video'" class="play-text"
|
@click="playVideo(row.videoFileKey, row.title)">点击播放
|
</div>
|
</template>
|
<template slot-scope="{ row, index }" slot="videoDuration">
|
<div>{{ formatSeconds(row.videoDuration) }}</div>
|
</template>
|
<template slot-scope="{ row, index }" slot="recommend">
|
<i-switch v-model="row.recommend" :before-change="() => handleBeforeChange(row)" true-color="#13ce66"/>
|
</template>
|
<template slot-scope="{ row, index }" slot="status">
|
{{ transStatus(row.status) }}
|
</template>
|
<template slot-scope="{ row, index }" slot="action">
|
<Button type="primary" size="small" style="margin-right: 5px" v-if="row.status === '99'"
|
@click="openAuditing(row)">审核
|
</Button>
|
<Button type="error" size="small" style="margin-right: 5px" v-if="row.status === '1'"
|
@click="openVideoDown(row)">下架
|
</Button>
|
<Button type="success" size="small" style="margin-right: 5px" v-else-if="row.status === '0'"
|
@click="videoUp(row)">上架
|
</Button>
|
</template>
|
</Table>
|
|
<Row type="flex" justify="end" class="mt_10">
|
<Page
|
:current="searchForm.pageNumber"
|
:total="total"
|
:page-size="searchForm.pageSize"
|
@on-change="changePage"
|
@on-page-size-change="changePageSize"
|
:page-size-opts="[10, 20, 50]"
|
size="small"
|
show-total
|
show-elevator
|
show-sizer
|
></Page>
|
</Row>
|
</Card>
|
</div>
|
</template>
|
|
<script>
|
import {getVideos, recommendSet, getVideoById, auditingVideo, up, down, recreateIndex,publish} from "@/api/video";
|
import {getVideoTagList, recommend, videoGoodsEsPage} from "@/api/videoTag";
|
import {getFilePreview, getSts} from "@/api/file";
|
import Editor from '@/components/editor/index.vue'
|
import GoodsExpandRow from '@/views/video/GoodsExpandRow'
|
import COS from "cos-js-sdk-v5";
|
import {getFileKey} from "@/utils/file";
|
import vuedraggable from "vuedraggable";
|
|
export default {
|
name: "VideoList",
|
components: {vuedraggable, Editor, GoodsExpandRow},
|
watch: {
|
'uploadVideoForm.videoContentType'(newValue, oldValue) {
|
if (newValue === 'video') {
|
this.showVideoFlag = true;
|
this.showImgFlag = false;
|
this.uploadVideoForm.videoImgs = []
|
this.uploadVideoForm.showListImages = []
|
} else {
|
this.uploadVideoForm.videoFileKey = '';
|
this.showVideoFlag = false;
|
this.showImgFlag = true;
|
this.videoProgress = 0;
|
}
|
},
|
chooseTag(newValue, oldValue) {
|
this.uploadVideoForm.tags = newValue.map(item => {
|
const findTag = this.videoTagList.find(tagItem => {
|
return tagItem.tagName === item
|
})
|
if (findTag) {
|
return {
|
id: findTag.id,
|
tagName: findTag.tagName
|
}
|
} else {
|
return {
|
id: "",
|
tagName: item,
|
}
|
}
|
})
|
console.log('------------------------------this.uploadVideoForm.tags>', this.uploadVideoForm.tags)
|
}
|
},
|
data() {
|
return {
|
endpoint: '',
|
searchGoods: '',
|
videoTagList: [],
|
chooseTag: '',
|
videoTag: '',
|
visible: false,
|
imgName: '',
|
showVideoFlag: true,
|
showImgFlag: false,
|
showVideoProgress: false,
|
videoProgress: 0,
|
upLoadVideoShow: false,
|
uploadVideoForm: {
|
id: '',
|
title: '',
|
cover: "",
|
videoFileKey: "",
|
videoDuration: 0,
|
videoFit: "cover",
|
videoContentType: 'video',
|
videoImgs: [],
|
showListImages: [],
|
tags: [],
|
fileInfo: {},
|
goodsList: []
|
|
},
|
videoDownForm: {
|
id: '',
|
reason: ''
|
},
|
videoDownRule: {
|
reason: [
|
{
|
require: true,
|
message: '请输入下架原因',
|
trigger: 'blur',
|
validator: (rule, value, callback) => {
|
if (value === null || value === '') {
|
callback(new Error('请输入下架原因'));
|
} else {
|
callback();
|
}
|
}
|
}
|
]
|
},
|
videoDownShow: false, // 视频下架
|
videoDownMsg: '', // 下架提示信息
|
auditingForm: { // 审核表单
|
id: null,
|
result: null,
|
reason: ''
|
},
|
auditingRule: {
|
result: [
|
{
|
required: true,
|
message: '请选择视频审核结果',
|
trigger: 'change',
|
validator: (rule, value, callback) => {
|
if (value === null || value === undefined) {
|
callback(new Error('请选择视频审核结果'));
|
} else {
|
callback();
|
}
|
}
|
}
|
],
|
},
|
detail: {}, // 视频详情信息
|
auditingShow: false, // 审核弹窗
|
auditingLoading: false, // 审核弹窗
|
playVideoShow: false, // 视频播放弹窗
|
playVideoTitle: '', // 视频播放标题
|
playVideoUrl: '', // 当前正在播放的视频地址
|
modelShow: false, // 弹窗显隐
|
modelTitle: '', // 弹窗title
|
loading: false, // 表单加载状态
|
searchForm: {
|
// 搜索框初始化对象
|
pageNumber: 1, // 当前页数
|
pageSize: 10, // 页面大小
|
title: '', // 标题
|
tagList: [], // 标签
|
status: '99'
|
},
|
searchGoodsForm: {
|
// 搜索框初始化对象
|
pageNumber: 1, // 当前页数
|
pageSize: 10, // 页面大小
|
keyword: '',
|
searchFromSelfStore: false
|
},
|
tagList: [], // 标签列表
|
columns: [
|
{
|
type: 'selection',
|
width: 60,
|
align: 'center'
|
},
|
{
|
width: 60,
|
type: 'expand',
|
render: (h, params) => {
|
return h(GoodsExpandRow, {
|
props: {
|
goodsList: params.row.goodsList
|
}
|
})
|
}
|
},
|
{
|
title: "标题",
|
key: "title",
|
minWidth: 240,
|
tooltip: true,
|
},
|
{
|
title: "作者",
|
key: "authorName",
|
width: 130,
|
tooltip: true,
|
},
|
{
|
title: "视频标签",
|
key: "tagList",
|
width: 180,
|
slot: "tagList",
|
},
|
{
|
title: "视频内容",
|
key: "videoFileKey",
|
width: 170,
|
slot: "videoFileKey"
|
},
|
{
|
title: "时长",
|
key: "videoDuration",
|
width: 80,
|
align: 'center',
|
slot: "videoDuration",
|
},
|
{
|
title: "播放量",
|
key: "playNum",
|
width: 80,
|
align: 'center'
|
},
|
{
|
title: "收藏数",
|
key: "collectNum",
|
width: 80,
|
align: 'center'
|
},
|
{
|
title: "评论数",
|
key: "commentNum",
|
width: 80,
|
align: 'center'
|
},
|
{
|
title: "首页推荐",
|
key: "recommend",
|
slot: "recommend",
|
width: 100,
|
align: 'center'
|
},
|
{
|
title: "权重",
|
key: "weight",
|
width: 80,
|
},
|
{
|
title: "状态",
|
key: "status",
|
slot: "status",
|
width: 120,
|
align: 'center'
|
},
|
{
|
title: "操作",
|
key: "action",
|
slot: "action",
|
align: "center",
|
width: 200,
|
},
|
],
|
goodsData: [],
|
data: [], // 表单数据
|
total: 0, // 表单数据总数
|
goodsTotal: 0, // 表单数据总数
|
selectCount: 0, // 已选数量
|
selectList: [], // 已选数据列表
|
}
|
},
|
created() {
|
this.getDataList();
|
this.getTags('')
|
},
|
methods: {
|
//todo 保留后续可能会使用
|
changeGoodsNum(id,index,goodsNum){
|
console.log('-------------------->',id,index,goodsNum)
|
},
|
chooseGoods(id) {
|
const goods = this.goodsData.find(item => {
|
return item.id === id;
|
})
|
const existingItem = this.uploadVideoForm.goodsList.find(item => item.goodsSkuId === id);
|
if (existingItem) {
|
existingItem.goodsNum = existingItem.goodsNum + 1;
|
} else {
|
this.uploadVideoForm.goodsList.push({
|
goodsId: goods.goodsId,
|
goodsSkuId: goods.id,
|
goodsNum: 1,
|
goodsName: goods.goodsName,
|
thumbnail: goods.thumbnail,
|
price: goods.price,
|
|
})
|
}
|
// this.uploadVideoForm.goodsList.forEach(item => {
|
// if (item.goodsSkuId === id) {
|
// item.goodsNum = item.goodsNum+1;
|
// }
|
// })
|
console.log('------------------------>', this.uploadVideoForm.goodsList)
|
|
|
},
|
searchGoodsList() {
|
this.searchGoodsForm.pageNumber = 1;
|
this.getGoodsDataList();
|
},
|
closeVideoUpload() {
|
this.upLoadVideoShow = false;
|
},
|
submitVideoUpload() {
|
this.uploadVideoForm.goodsList = this.uploadVideoForm.goodsList.filter(item => {
|
return item.goodsNum >0;
|
})
|
publish(this.uploadVideoForm).then(response => {
|
if (response.code == 200) {
|
this.$Message.success("视频发布成功");
|
this.upLoadVideoShow = false;
|
this.getDataList();
|
}
|
}).then(error=>{
|
this.$Message.success(error);
|
})
|
},
|
//todo 后续可能会使用预留
|
createVideoTag(e) {
|
},
|
handleRemove(file) {
|
const fileList2 = this.uploadVideoForm.showListImages;
|
this.uploadVideoForm.videoImgs.splice(fileList2.indexOf(file), 1);
|
this.uploadVideoForm.showListImages.splice(fileList2.indexOf(file), 1);
|
},
|
handleView(name) {
|
this.imgName = name;
|
this.visible = true;
|
},
|
async upLoadImg(file) {
|
if (this.uploadVideoForm.videoImgs >= 5) {
|
this.$Message.error("图片上传不能超过5个");
|
return;
|
}
|
try {
|
// this.upLoadVideoLoading = true;
|
// 获取文件上传临时密钥
|
const sts = await getSts();
|
const cos = new COS({
|
getAuthorization: async function (options, callback) {
|
callback({
|
TmpSecretId: sts.data.tmpSecretId,
|
TmpSecretKey: sts.data.tmpSecretKey,
|
SecurityToken: sts.data.sessionToken,
|
// 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
|
StartTime: sts.data.stsStartTime, // 时间戳,单位秒,如:1580000000
|
ExpiredTime: sts.data.stsEndTime,// 时间戳,单位秒,如:1580000000
|
ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
|
});
|
}
|
})
|
const fileKey = getFileKey(file.name)
|
const upData = await cos.uploadFile({
|
Bucket: sts.data.bucket,
|
Region: sts.data.region,
|
Key: fileKey,
|
Body: file, // 要上传的文件对象。
|
SliceSize: 1024 * 1024 * 5,
|
onProgress: function (progressData) {
|
console.log('上传进度:', progressData);
|
},
|
});
|
console.log("上传成功", upData)
|
this.$nextTick(() => {
|
this.uploadVideoForm.videoImgs.push(fileKey);
|
this.uploadVideoForm.showListImages.push(sts.data.endpoint + "/" + fileKey);
|
})
|
|
} catch (e) {
|
console.log("上传失败", upData)
|
return false;
|
} finally {
|
// this.upLoadVideoLoading = false;
|
|
}
|
return false;
|
},
|
reloadVideo() {
|
this.uploadVideoForm.videoFileKey = '';
|
this.uploadVideoForm.showVideoUrl = '';
|
},
|
calculateVideoFit(width, height) {
|
const videoRatio = width / height;
|
// 规则2:竖屏视频(如9:16)
|
if (videoRatio < 0.8) return 'cover';
|
return 'contain';
|
},
|
getVideoDuration(e) {
|
const duration = this.$refs.videoInfo.duration;
|
const videoWidth = this.$refs.videoInfo.videoWidth;
|
const videoHeight = this.$refs.videoInfo.videoHeight;
|
// 根据宽高比选择视频填充模式
|
const fitType = this.calculateVideoFit(videoWidth, videoHeight)
|
this.uploadVideoForm.videoFit = fitType
|
console.log('------视频信息3------------>', videoWidth, videoHeight, fitType)
|
|
this.uploadVideoForm.videoDuration = Math.floor(duration);
|
},
|
async upLoadVideo(file) {
|
try {
|
this.$nextTick(() => {
|
this.showVideoProgress = true;
|
})
|
// 获取文件上传临时密钥
|
const sts = await getSts();
|
const cos = new COS({
|
getAuthorization: async function (options, callback) {
|
callback({
|
TmpSecretId: sts.data.tmpSecretId,
|
TmpSecretKey: sts.data.tmpSecretKey,
|
SecurityToken: sts.data.sessionToken,
|
// 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
|
StartTime: sts.data.stsStartTime, // 时间戳,单位秒,如:1580000000
|
ExpiredTime: sts.data.stsEndTime,// 时间戳,单位秒,如:1580000000
|
ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
|
});
|
}
|
})
|
const fileKey = getFileKey(file.name)
|
const upData = await cos.uploadFile({
|
Bucket: sts.data.bucket,
|
Region: sts.data.region,
|
Key: fileKey,
|
Body: file, // 要上传的文件对象。
|
SliceSize: 1024 * 1024 * 5,
|
onProgress: (progressData) => {
|
console.log('上传进度:', progressData);
|
this.videoProgress = Math.floor(progressData.percent * 100);
|
},
|
});
|
|
console.log(this.uploadVideoForm)
|
this.$nextTick(() => {
|
this.uploadVideoForm.videoFileKey = fileKey;
|
this.uploadVideoForm.showVideoUrl = sts.data.endpoint + "/" + fileKey;
|
})
|
console.log("上传成功", upData)
|
const duration = this.$refs.healthVideoInfo.duration;
|
console.log('-测试获取时间信息---------------->', duration);
|
} catch (e) {
|
console.log("上传失败", upData)
|
} finally {
|
this.$nextTick(() => {
|
this.showVideoProgress = false;
|
})
|
}
|
return false;
|
},
|
openUploadVideo() {
|
this.upLoadVideoShow = true;
|
this.videoTagList = []
|
this.uploadVideoForm = {
|
id: '',
|
title: '',
|
cover: "",
|
videoFileKey: "",
|
videoDuration: 0,
|
videoFit: "cover",
|
videoContentType: 'video',
|
videoImgs: [],
|
showListImages: [],
|
tags: [],
|
fileInfo: {},
|
goodsList: []
|
}
|
recommend({
|
searchType: "HOT"
|
}).then(res => {
|
this.videoTagList = res.data;
|
})
|
this.searchGoodsList();
|
},
|
recreateEsIndex() {
|
recreateIndex().then(res => {
|
this.$Message.success(res.msg)
|
})
|
},
|
// 秒转x分x秒
|
formatSeconds(seconds) {
|
if (isNaN(seconds) || seconds < 0) return '0秒';
|
|
const mins = Math.floor(seconds / 60);
|
const secs = seconds % 60;
|
|
if (mins === 0) return `${secs}秒`;
|
if (secs === 0) return `${mins}分`;
|
|
return `${mins}分${secs}秒`;
|
},
|
// 获取标签列表
|
getTags(tagName) {
|
let params = {
|
'tagName': tagName
|
}
|
getVideoTagList(params).then(res => {
|
this.tagList = res.data
|
})
|
},
|
// 获取富文本编辑器的内容
|
getReason(content) {
|
this.videoDownForm.reason = content
|
},
|
// 视频上架
|
videoUp(row) {
|
this.$Modal.confirm({
|
title: "操作确认",
|
content: "您确认要上架视频【 " + row.title + "】吗?",
|
loading: true,
|
onOk: () => {
|
up(row.id).then(res => {
|
this.$Modal.remove();
|
if (res.code == 200) {
|
this.$Message.success("视频上架成功");
|
this.getDataList();
|
}
|
});
|
}
|
});
|
},
|
// 视频下架
|
videoDown() {
|
this.$refs.videoDownForm.validate((valid) => {
|
if (valid) {
|
down(this.videoDownForm).then(res => {
|
this.$Message.success("下架成功")
|
this.closeVideoDown()
|
this.getDataList()
|
})
|
}
|
})
|
},
|
// 关闭视频下架
|
closeVideoDown() {
|
this.videoDownShow = false
|
this.videoDownForm = {
|
id: '',
|
reason: ''
|
}
|
this.$refs.editor.setContent('')
|
},
|
// 视频下架
|
openVideoDown(row) {
|
this.videoDownForm.id = row.id
|
this.videoDownShow = true
|
},
|
// 提交审核结果
|
submitAuditing() {
|
console.log(this.auditingForm, "sb")
|
this.$refs.auditingForm.validate((valid) => {
|
if (valid) {
|
auditingVideo(this.auditingForm).then(res => {
|
this.$Message.success("审核完成")
|
this.closeAuditing()
|
this.getDataList()
|
})
|
}
|
})
|
},
|
// 审核结果变化
|
resultChange(selected) {
|
this.auditingForm.result = selected === '通过' ? 1 : 0
|
console.log(this.auditingForm.result)
|
},
|
closeAuditing() {
|
this.auditingForm = {
|
id: null,
|
result: null,
|
reason: ''
|
}
|
this.detail = {}
|
this.auditingShow = false
|
},
|
// 打开审核弹窗
|
openAuditing(row) {
|
this.auditingShow = true
|
this.auditingLoading = true
|
this.auditingForm.id = row.id
|
getVideoById(row.id).then(res => {
|
this.detail = res.data
|
this.auditingLoading = false
|
})
|
},
|
// 翻译状态
|
transStatus(status) {
|
switch (status) {
|
case '99':
|
return '待审核'
|
case '1':
|
return '已发布'
|
case '0':
|
return '已下架'
|
case '-1':
|
return '审核未通过'
|
default:
|
return '未知'
|
}
|
},
|
// 开启或关闭推荐的方法
|
handleBeforeChange(row) {
|
let content = ""
|
if (row.recommend) {
|
content = '确认要关闭首页推荐吗?'
|
} else {
|
content = '确认要开启首页推荐吗?'
|
}
|
return new Promise((resolve) => {
|
this.$Modal.confirm({
|
title: '操作提醒',
|
content: content,
|
onOk: () => {
|
recommendSet({id: row.id, recommend: !row.recommend}).then(res => {
|
this.$Message.success(res.msg);
|
resolve();
|
})
|
}
|
});
|
});
|
},
|
// 关闭视频播放
|
playVideoClose() {
|
this.playVideoTitle = '';
|
this.playVideoUrl = '';
|
this.playVideoShow = false
|
},
|
// 点击播放视频
|
playVideo(fileKey, title) {
|
this.playVideoTitle = title;
|
|
getFilePreview(fileKey).then(res => {
|
this.playVideoUrl = res.data
|
this.playVideoShow = true
|
})
|
},
|
// 搜索
|
handleSearch() {
|
this.searchForm.pageNumber = 1;
|
this.searchForm.pageSize = 10;
|
this.getDataList();
|
},
|
// 获取列表数据
|
getGoodsDataList() {
|
let search = this.searchGoodsForm;
|
if (search.pageNumber > 0) {
|
search.pageNumber = search.pageNumber - 1;
|
}
|
videoGoodsEsPage(search).then((res) => {
|
console.log(res)
|
this.loading = false;
|
if (res.code == 200) {
|
this.goodsData = res.data;
|
getSts().then(res => {
|
this.endpoint = res.data.endpoint
|
})
|
this.goodsTotal = res.total;
|
}
|
});
|
this.total = this.data.length;
|
},
|
// 获取列表数据
|
getDataList() {
|
this.loading = true;
|
getVideos(this.searchForm).then((res) => {
|
console.log(res)
|
this.loading = false;
|
if (res.code == 200) {
|
this.data = res.data;
|
this.total = res.total;
|
}
|
});
|
this.total = this.data.length;
|
this.loading = false;
|
},
|
showSelect(e) {
|
this.selectList = e.map(d => d.id);
|
this.selectCount = e.length;
|
},
|
// 排序
|
changeSort(e) {
|
this.searchForm.sort = e.key;
|
this.searchForm.order = e.order;
|
if (e.order == "normal") {
|
this.searchForm.order = "";
|
}
|
this.getDataList();
|
},
|
// 分页 改变页码
|
changePage(v) {
|
this.searchForm.pageNumber = v;
|
this.getDataList();
|
},
|
// 分页 改变页数
|
changePageSize(v) {
|
this.searchForm.pageNumber = 1;
|
this.searchForm.pageSize = v;
|
this.getDataList();
|
},
|
// 分页 改变页码
|
goodsChangePage(v) {
|
this.searchForm.pageNumber = v;
|
this.getGoodsDataList();
|
},
|
// 分页 改变页数
|
goodsChangePageSize(v) {
|
this.searchForm.pageNumber = 1;
|
this.searchForm.pageSize = v;
|
this.getGoodsDataList();
|
},
|
}
|
}
|
</script>
|
|
<style scoped>
|
.play-text {
|
width: 100%;
|
text-align: center;
|
color: #2d8cf0;
|
}
|
|
.play-text:hover {
|
cursor: pointer;
|
}
|
|
.video-warp {
|
width: 100%;
|
height: 440px;
|
}
|
|
.data-item {
|
display: flex;
|
align-items: center;
|
}
|
|
.img-warp {
|
padding: 10px;
|
}
|
|
.image {
|
width: 150px;
|
height: 200px;
|
}
|
|
.demo-upload-list {
|
display: inline-block;
|
width: 60px;
|
height: 60px;
|
text-align: center;
|
line-height: 60px;
|
border: 1px solid transparent;
|
border-radius: 4px;
|
overflow: hidden;
|
background: #fff;
|
position: relative;
|
box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
|
margin-right: 4px;
|
}
|
|
.demo-upload-list img {
|
width: 100%;
|
height: 100%;
|
}
|
|
.demo-upload-list-cover {
|
display: none;
|
position: absolute;
|
top: 0;
|
bottom: 0;
|
left: 0;
|
right: 0;
|
background: rgba(0, 0, 0, .6);
|
}
|
|
.demo-upload-list:hover .demo-upload-list-cover {
|
display: block;
|
}
|
|
.demo-upload-list-cover i {
|
color: #fff;
|
font-size: 20px;
|
cursor: pointer;
|
margin: 0 2px;
|
}
|
</style>
|