2025-02-27 20:10:10 +08:00

722 lines
21 KiB
Vue

<template>
<div class="app-container">
<div class="mb10">
<el-input
v-model="queryParams.title"
class="w260 mb10"
clearable
placeholder="请输入直播标题名称"
/>
<el-select
v-model="queryParams.playType"
class="mb10"
clearable
filterable
placeholder="播放类型"
>
<el-option
v-for="item in playTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<el-select
v-model="queryParams.liveStatus"
class="mb10"
clearable
filterable
placeholder="直播状态"
>
<el-option
v-for="item in liveStatusList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<el-select
v-model="queryParams.status"
class="mb10"
clearable
filterable
placeholder="审核状态"
>
<el-option
v-for="item in statusList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<el-select
v-if="!settingToC"
v-model="queryParams.tagId"
class="mb10"
filterable
remote
reserve-keyword
placeholder="标签"
:remote-method="remoteMethodTag"
:loading="loadingTag"
>
<el-option
v-for="item in optionsTag"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
<el-button type="primary" @click="searchList()">查询</el-button>
<el-button type="success" @click="toCreate()">新增</el-button>
<el-dropdown @command="toBatchCreate">
<el-button
type="primary"
style="background-color: rgb(72, 153, 208);color:white;"
>
批量新增<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="2">横屏直播</el-dropdown-item>
<!-- <el-dropdown-item command="1">竖屏直播</el-dropdown-item> -->
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="mb10">
<el-table v-loading="loading" :data="data" border style="width: 100%">
<el-table-column label="序号" type="index" fixed width="50">
</el-table-column>
<el-table-column prop="startTime" label="直播开始时间" width="180">
<template slot-scope="scope">
{{ scope.row.startTime ? scope.row.startTime : "--" }}
</template>
</el-table-column>
<el-table-column prop="title" label="标题" width="180">
<template slot-scope="scope">
<el-button
type="text"
style="white-space: normal;"
@click="toDetail(scope.row)"
>{{ scope.row.title }}</el-button
>
</template>
</el-table-column>
<!-- <el-table-column
prop="viewPoint"
label="简介"
width="180">
</el-table-column> -->
<el-table-column prop="imgUrl" label="封面" width="100">
<template #default="scope">
<el-popover placement="right" :width="400" trigger="hover">
<img :src="scope.row.imgUrl" width="375" height="300" />
<template #reference>
<img
:src="scope.row.imgUrl"
style="max-height: 60px; max-width: 60px"
/>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="name" label="直播状态" width="180">
<template slot-scope="scope">
{{
scope.row.playType === 1 ? liveLabel[scope.row.liveStatus] : "--"
}}
</template>
</el-table-column>
<el-table-column
v-if="!settingToC"
prop="name"
label="标签"
width="180"
>
<template slot-scope="scope">
<span v-for="item in scope.row.tagVOList" :key="item.id">{{
item.name + " "
}}</span>
</template>
</el-table-column>
<el-table-column
v-if="!settingToC"
prop="name"
label="是否为专栏直播"
width="180"
>
<template slot-scope="scope">
{{ scope.row.columnId ? "是" : "否" }}
</template>
</el-table-column>
<el-table-column
v-if="!settingToC"
prop="name"
label="所属专栏"
width="180"
>
<template slot-scope="scope">
{{ scope.row.columnName }}
</template>
</el-table-column>
<el-table-column prop="name" label="播放类型" width="180">
<template slot-scope="scope">
{{ scope.row.playType === 1 ? "直播" : "录播" }}
</template>
</el-table-column>
<el-table-column prop="name" label="购物车产品数量" width="180">
<template slot-scope="scope">
<el-button type="text" @click="toProductList(scope.row)">
{{
scope.row.cartVOList.length ? scope.row.cartVOList.length : 0
}}</el-button
>
</template>
</el-table-column>
<el-table-column prop="name" label="观看限制" width="180">
<template slot-scope="scope">
{{ limitTypeList[scope.row.limitType] }}
</template>
</el-table-column>
<el-table-column prop="endTime" label="直播结束时间" width="180">
<template slot-scope="scope">
{{ scope.row.endTime ? scope.row.endTime : "--" }}
</template>
</el-table-column>
<el-table-column prop="subscribeUserCount" label="预约人数" width="180">
</el-table-column>
<el-table-column prop="name" label="风险等级" width="180">
<template slot-scope="scope">
{{ riskLevelList[scope.row.riskLevel] }}
</template>
</el-table-column>
<el-table-column prop="name" label="产品状态" width="180">
<template slot-scope="scope">
{{ statusListLabel[scope.row.status] }}
</template>
</el-table-column>
<el-table-column prop="auditTime" label="审核时间" width="180">
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180">
</el-table-column>
<el-table-column prop="transStatus" label="转码状态" width="180">
<template slot-scope="scope">
{{
scope.row.transStatus === 1
? "转码中"
: scope.row.transStatus === 2
? "已转码"
: "--"
}}
</template>
</el-table-column>
<el-table-column
prop="name"
label="操作"
fixed="right"
align="center"
width="400"
>
<template slot-scope="scope">
<el-button
v-if="[3, 5, 6].includes(scope.row.status)"
type="text"
@click="toCreate(scope.row.id, 2)"
>查看</el-button
>
<el-button
v-if="[3].includes(scope.row.status)"
type="text"
@click="downloadByBlob(scope.row)"
>下载海报</el-button
>
<el-button
v-if="[3].includes(scope.row.status)"
class="tag"
type="text"
@click="copyUrl($event, scope.row)"
>{{
scope.row.playType === 1 ? "复制直播链接" : "复制视频链接"
}}</el-button
>
<el-button
v-if="
[3].includes(scope.row.status) &&
scope.row.playType === 1 &&
scope.row.liveStatus !== 4
"
type="text"
@click="openPlayInfo(scope.row)"
>推流</el-button
>
<el-button
v-if="[3, 5].includes(scope.row.status)"
type="text"
@click="openProduct(scope.row)"
>{{ scope.row.playType === 1 ? "单场分析" : "数据" }}</el-button
>
<el-button
v-if="
[3, 5].includes(scope.row.status) && scope.row.playType === 1
"
type="text"
@click="toDateDetail(scope.row)"
>实时大屏</el-button
>
<el-button
v-if="[1, 4].includes(scope.row.status)"
type="text"
@click="listing(scope.row)"
>申请上架</el-button
>
<el-button
v-if="[2].includes(scope.row.status)"
type="text"
@click="listing(scope.row)"
>撤回</el-button
>
<el-button
v-if="[1, 4].includes(scope.row.status)"
type="text"
@click="toCreate(scope.row.id, 1)"
>修改</el-button
>
<el-button type="text" @click="copyProduct(scope.row.id)"
>复制</el-button
>
</template>
</el-table-column>
<el-table-column prop="reason" label="备注" width="180">
</el-table-column>
</el-table>
</div>
<!--分页组件-->
<el-pagination
:total="total"
:current-page="queryParams.current"
:page-size="queryParams.size"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<el-dialog
title="带货产品清单"
:visible.sync="dialogTableVisible"
:modal-append-to-body="false"
>
<el-table :data="gridData">
<el-table-column type="index" label="序号"></el-table-column>
<el-table-column
property="productName"
label="产品名称"
></el-table-column>
<el-table-column property="productType" label="产品类型">
<template slot-scope="scope">
{{ productTypeList[scope.row.productType] }}
</template>
</el-table-column>
<el-table-column label="投顾名称">
<template slot-scope="scope">
{{ scope.row.advisorBasic ? scope.row.advisorBasic.name : "" }}
</template>
</el-table-column>
<el-table-column
property="count"
label="本场直播点击数"
></el-table-column>
<el-table-column
property="subCount"
label="本场直播订阅数"
></el-table-column>
</el-table>
</el-dialog>
<el-dialog
title="推流"
:visible.sync="dialogInputVisible"
:modal-append-to-body="false"
>
<el-form ref="form" :model="dialogForm" label-width="80px">
<el-form-item label="推流地址">
<div>{{ dialogForm.pushUrl }}</div>
<el-button
type="text"
class="tag"
style="margin-left:10px;"
@click="copyUrlTwo($event, dialogForm.pushUrl, 1)"
>复制服务器地址</el-button
>
<el-button
type="text"
class="tag"
style="margin-left:10px;"
@click="copyUrlTwo($event, dialogForm.pushUrl, 2)"
>复制推流码</el-button
>
</el-form-item>
<el-form-item label="播流地址">
{{ dialogForm.playUrl }}
</el-form-item>
</el-form>
</el-dialog>
<el-dialog
v-if="showQrCode"
:visible.sync="showQrCode"
append-to-body
width="400px"
title="生成二维码"
>
<QrCode ref="QrCode" />
</el-dialog>
<DownVideo
ref="downVideoRef"
:video-detail="cVideoDetail"
@updateTranStatus="updateTranStatus"
/>
</div>
</template>
<script>
import {
getInfoList,
tagList,
livePlayInfo,
infoSubmit,
infoRecall,
infoGet,
urlResize
} from "@/api/videoLive";
import QrCode from "@/components/QrCode";
import { mapGetters, mapState } from "vuex";
import { handleClipboard } from "../manage/config";
import { cryptoDecode } from "@/utils/crypto.js";
import DownVideo from "../manage/components/DownVideo.vue";
export default {
components: {
QrCode,
DownVideo
},
data() {
return {
queryParams: {
current: 1,
size: 10,
userType: 1
},
total: 1,
loading: false,
showQrCode: false,
playTypeList: [{ value: 1, label: "直播" }, { value: 2, label: "录播" }],
liveStatusList: [
{ value: 1, label: "直播中" },
{ value: 2, label: "未开始" },
{ value: 3, label: "暂停中" },
{ value: 4, label: "已结束" }
],
statusList: [
{ value: 1, label: "待提交" },
{ value: 2, label: "待审核" },
{ value: 3, label: "已上架" },
{ value: 4, label: "已驳回" },
{ value: 5, label: "已下架" }
],
statusListLabel: ["", "待提交", "待审核", "已上架", "已驳回", "已下架"],
liveLabel: ["", "直播中", "未开始", "暂停中", "已结束"],
limitTypeList: {
1: "不限制",
2: "手机号",
3: "邀请码",
4: "微信授权",
5: "产品专属直播"
},
riskLevelList: {
1: "低风险",
2: "中低风险",
3: "中风险",
4: "中高风险",
5: "高风险"
},
tagIdList: [],
data: [],
gridData: [],
dialogTableVisible: false,
dialogInputVisible: false,
optionsTag: [],
loadingTag: false,
dialogForm: {
pushUrl: "",
playUrl: ""
},
productTypeList: {
1: "观点包",
21: "自定义"
},
copyText: "",
cVideoDetail: {} // 点击下载按钮的视频详情
};
},
computed: {
...mapGetters(["user"]),
...mapState({
settingToC: state => state.settings.settingToC
})
},
mounted() {
this.queryList();
this.remoteMethodTag("");
},
methods: {
cryptoDecode,
queryList() {
this.loading = true;
getInfoList(this.queryParams).then(data => {
this.data = data.data.list;
this.total = data.data.total;
this.loading = false;
});
},
searchList() {
this.queryParams.size = 10;
this.queryParams.current = 1;
this.queryParams.userType = 1;
this.queryList();
},
handleSizeChange(val) {
this.$set(this.queryParams, "size", val);
this.$set(this.queryParams, "current", 1);
this.queryList();
},
handleCurrentChange(val) {
this.$set(this.queryParams, "current", val || 1);
this.queryList();
},
openProduct(val) {
window.open(
`${location.origin +
location.pathname}#/liveBroadcast/liveBroadcastDetail?id=${
val.id
}&type=1`
);
// this.$router.push(`/liveBroadcast/liveBroadcastDetail?id=${val.id}&type=1`)
},
toCreate(id, type) {
// type = 2 查看
if (id && type) {
this.$router.push(
`/liveBroadcast/liveBroadcastCreate?id=${id}&type=${type}&userType=1`
);
} else {
this.$router.push(`/liveBroadcast/liveBroadcastCreate?userType=1`);
}
},
toBatchCreate(command) {
this.$router.push(
`/liveBroadcast/liveBroadcastBatchCreate?playStyle=${command}`
);
},
remoteMethodTag(query) {
this.loadingTag = true;
const queryParams = {
name: query,
current: 1,
size: 10,
type: 3,
status: 1
};
tagList(queryParams).then(data => {
this.optionsTag = data.data.list;
this.loadingTag = false;
});
},
openPlayInfo(item) {
livePlayInfo({ id: item.id }).then(res => {
if (res.code === 0) {
this.dialogForm.pushUrl = res.data.pushUrl;
this.dialogForm.playUrl = res.data.playUrl;
this.dialogInputVisible = true;
}
});
},
listing(item) {
this.$confirm(
`您确定提交${[1, 4].includes(item.status) ? "申请上架" : "撤回"}?`,
{
confirmButtonText: "提交",
cancelButtonText: "取消",
type: "warning"
}
)
.then(() => {
// 申请上架
if ([1, 4].includes(item.status)) {
infoSubmit({ videoId: item.id }).then(res => {
if (res.code === 0) {
this.$message({
type: "success",
message: "申请上架成功!"
});
this.searchList();
}
});
} else {
// 撤回
infoRecall({ id: item.id }).then(res => {
if (res.code === 0) {
this.$message({
type: "success",
message: "撤回成功!"
});
this.searchList();
}
});
}
})
.catch(() => {});
},
toProductList(item) {
infoGet({ id: item.id }).then(res => {
if (res.code === 0) {
this.gridData = res.data.cartVOList;
this.dialogTableVisible = true;
} else {
this.$message.error("获取带货产品失败!");
}
});
},
// 下载海报
downloadByBlob(val) {
this.showQrCode = true;
// const url = `${window.location.origin}/syzbh5/videoPlay?id=${this.cryptoDecode(val.id)}&saleUserId=${this.user.user.id}`
const url = `${window.location.origin}/syzbh5/videoPlay?id=${
val.id
}&saleUserId=${this.user.user.id}`;
this.$nextTick(() => {
this.$refs.QrCode.createCode(url);
});
},
download(href, name) {
const eleLink = document.createElement("a");
eleLink.download = name;
eleLink.href = href;
eleLink.click();
eleLink.remove();
},
async copyUrl(event, item) {
// const currentTarget = event.currentTarget
// let res = await livePlayInfo({ id: item.id })
// if (res.code === 0) {
// handleClipboard(res.data.playUrl, event, currentTarget)
// }
const currentTarget = event.currentTarget;
// let res = await livePlayInfo({ id: item.id })
// if (res.code === 0) {
// handleClipboard(res.data.playUrl, event, currentTarget)
// }
// const url = `${window.location.origin}/syzbh5/videoPlay?id=${this.cryptoDecode(item.id)}&saleUserId=${this.user.user.id}`
const ret = await urlResize({
url: `/videoPlay?id=${item.id}`
});
if (ret.code === 0) {
handleClipboard(ret.data, event, currentTarget);
}
},
copyUrlTwo(event, url, type) {
const currentTarget = event.currentTarget;
const splitUrl = JSON.parse(JSON.stringify(url));
var regex = /^(.*)\/(\d+)\?/;
var match = splitUrl.match(regex);
// type 1 服务器地址 2 推流码
if (type === 1 && match[1]) {
handleClipboard(match[1], event, currentTarget);
} else {
handleClipboard(
this.extractAfterSlashNumber(url),
event,
currentTarget
);
}
},
extractAfterSlashNumber(rtmpUrl) {
// 使用正则表达式匹配最后一个/开始到URL末尾的所有内容
var regex = /([\d]+\?.*)$/;
var match = rtmpUrl.match(regex);
if (match && match.length > 1) {
// 返回匹配到的部分(即/数字?及之后的所有内容)
return match[1];
} else {
// 如果没有匹配到,返回空字符串或错误信息
return ""; // 或者 'Error: No match found';
}
},
toDetail(val) {
this.$router.push(`/liveBroadcast/liveDetail?id=${val.id}&type=1`);
},
toDateDetail(val) {
window.open(
`${location.origin + location.pathname}#/largeScreen/index?videoId=${
val.id
}&type=1`
);
},
copyProduct(id) {
this.$confirm(`将复制直播信息,直播数据将不会同步`, {
confirmButtonText: "确认",
cancelButtonText: "取消"
})
.then(() => {
this.$router.push(
`/liveBroadcast/liveBroadcastCreate?id=${id}&userType=1&isCopy=true`
);
})
.catch(() => {});
},
downVideoFn(row) {
this.cVideoDetail = row;
this.$refs.downVideoRef.dialogVisible = true;
},
updateTranStatus(downloadStatus) {
this.cVideoDetail.downloadStatus = downloadStatus;
}
}
};
</script>
<style scoped lang="scss">
.mb10 {
margin-bottom: 10px;
}
.flex-box {
display: inline-flex;
flex-direction: row;
&_item {
display: inline-flex;
flex-direction: column;
margin-right: 10px;
cursor: pointer;
background-color: rgb(255, 255, 255);
align-self: center;
div {
padding: 5px 0;
display: inline-flex;
align-self: center;
}
}
}
.charts-box {
padding: 20px;
width: 60%;
}
.w260 {
width: 260px;
}
</style>