直播管理 #39

Merged
asd merged 1 commits from zj into master 2020-10-14 09:00:57 +08:00
5 changed files with 628 additions and 414 deletions

View File

@ -1,6 +1,6 @@
import router from '@/router'; import router from '@/router';
import store from '@/store'; import store from '@/store';
import { LoginData, UserInfo } from '@/types'; import { LiveList, LoginData, UserInfo } from '@/types';
import { saveValue } from '@/utils/common'; import { saveValue } from '@/utils/common';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { get, post, setToken } from './base' import { get, post, setToken } from './base'
@ -132,35 +132,12 @@ export async function getvideolist() {
* *
*/ */
interface LiveList {
liveid: number;
memberid: number;
title: string;
img: string;
fileid: string;
fileurl: string;
fileduration: string;
vodurl: string;
vodid: string;
vodduration: string;
dateline: string;
livetime: number;
livenumber: number;
status: number;
livestatus: number;
students: string;
desc: string;
deleted_at: null;
created_at: string;
updated_at: string;
statusname: string;
starttime: string;
begin: number;
}
export async function getlivelist() {
const res = await get<Array<LiveList>>('live'); export async function getlivelist(data?:any) {
console.log(res); const res = await get<Array<LiveList>>('live',data);
// console.log(res);
return res.data
} }
/** /**
@ -182,3 +159,15 @@ export async function getstatisticlist() {
studentInfo:res.data?.studentInfo studentInfo:res.data?.studentInfo
} }
} }
/**
*
*/
interface Liveaddrule{
code:number,
msg:string
}
export async function liveadd(data:any) {
const res = await post<Liveaddrule>('live',data);
console.log(res)
}

View File

@ -1,34 +1,34 @@
<template> <template>
<div class="videoitem" @click="navto()"> <div class="videoitem" @click="navto()">
<img src="" alt="" class="cover"> <img :src="img" alt="" class="cover">
<img src="@/static/images/play.png" alt="" class="play"> <img src="@/static/images/play.png" alt="" class="play">
<div class="title"> <div class="title">
sadghaskghdfjkaghjkfha {{title}}
<span class="lv">7.3</span> <span class="lv">{{score}}</span>
</div> </div>
<div class="info"> <div class="info">
<div class="datetime"> <div class="datetime">
<span>2020-09-11</span> <span>{{date.split(" ")[0]}}</span>
<span class="time">09:30</span> <span class="time">{{date.split(" ")[1]}}</span>
</div> </div>
<div class="feature"> <div class="feature">
<div> <div>
<img src="@/static/images/shijian.png" alt=""> <img src="@/static/images/shijian.png" alt="">
<span>123</span> <span>{{takehour}}</span>
</div> </div>
<div> <div>
<img src="@/static/images/studentnum.png" alt=""> <img src="@/static/images/studentnum.png" alt="">
<span>3</span> <span>{{livenum}}</span>
</div> </div>
</div> </div>
</div> </div>
<div class="state audit" v-if="type==1"> <div class="state audit" v-if="status==0">
还未开始 还未开始
</div> </div>
<div class="state live" v-if="type==2"> <div class="state live" v-if="status==1">
进入直播 进入直播
</div> </div>
<div class="state over" v-if="type==3"> <div class="state over" v-if="status==2">
查看回放 查看回放
</div> </div>
</div> </div>
@ -141,6 +141,27 @@ export default defineComponent({
type: { type: {
type: Number, type: Number,
default:1 default:1
},
img:{
type:String
},
title:{
type:String
},
score:{
type:Number
},
date:{
type:String
},
takehour:{
type:String
},
livenum:{
type:Number
},
status:{
type:Number
} }
}, },
setup(props){ setup(props){

27
src/types/index.d.ts vendored
View File

@ -61,3 +61,30 @@ export interface UserInfo {
desc: string; desc: string;
money: string; money: string;
} }
export interface LiveList {
liveid: number;
memberid: number;
title: string;
img: string;
fileid: string;
fileurl: string;
fileduration: string;
vodurl: string;
vodid: string;
vodduration: string;
dateline: string;
livetime: number;
livenumber: number;
status: number;
livestatus: number;
students: string;
desc: string;
deleted_at: null;
created_at: string;
updated_at: string;
statusname: string;
starttime: string;
begin: number;
}

View File

@ -1,379 +1,560 @@
<template> <template>
<div class="webcast"> <div class="webcast">
<a-form :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form :label-col="labelCol" :wrapper-col="wrapperCol">
<div class="title">直播信息</div> <div class="title">直播信息</div>
<a-form-item label="直播标题"> <a-form-item label="直播标题">
<a-input size="small" v-model:value="form.title" placeholder="请输入您的直播标题" /> <a-input
</a-form-item> size="small"
<a-form-item label="直播封面" class="item-cover"> v-model:value="form.title"
<a-upload placeholder="请输入您的直播标题"
list-type="picture" />
@change="coverChange" </a-form-item>
action="//jsonplaceholder.typicode.com/posts/" <a-form-item label="直播封面" class="item-cover">
> <a-upload list-type="picture" :customRequest="uploadspic">
<div class="upload-image" v-if="!viewCover"> <div class="upload-image" v-if="!viewCover && form.img.length == 0">
<PlusOutlined style="fontSize: 22px;" /> <PlusOutlined
</div> style="fontsize: 22px"
<div class="preview-image" v-else> v-if="uploadpicprogress == 0"
<img style="width: 100%" :src="previewImage" /> />
</div> <a-progress
</a-upload> type="circle"
</a-form-item> :percent="uploadpicprogress"
<a-form-item label="视频介绍" class="video-introduction"> :width="80"
<a-upload v-else
list-type="picture" />
action="//jsonplaceholder.typicode.com/posts/" </div>
> <div class="upload-image" v-else>
<div class="upload-image"> <img style="width: 100%; height: 100%" :src="form.img" />
<PlaySquareOutlined style="fontSize: 22px;" /> </div>
</div> </a-upload>
</a-upload> </a-form-item>
<div class="demand"> <a-form-item label="视频介绍" class="video-introduction">
<p class="one-line-hide">视频要求</p> <a-upload list-type="picture" :customRequest="uploads">
<p class="one-line-hide"> 1.上传视频时间要求为30s之内</p> <div class="upload-image" v-if="form.fileurl.length == 0">
<p class="one-line-hide">2.支持文件大小100M</p> <PlaySquareOutlined
<p class="one-line-hide">3.文件扩展名fivmp4文件扩展名fivmp4</p> style="fontsize: 22px"
</div> v-if="uploadprogress == 0"
</a-form-item> />
<a-form-item label="开始时间"> <a-progress
<a-input size="small" v-model:value="form.startTime" placeholder="请设置您的开始时间" /> type="circle"
</a-form-item> :percent="uploadprogress"
<a-form-item label="直播时长" class="duration" v-bind="validateInfos.duration"> :width="80"
<a-input size="small" v-model:value="form.duration" placeholder="请输入直播时间" /> v-else
<span class="unit">分钟</span> />
</a-form-item> <video style="display: none" :src="videofile"></video>
<a-form-item label="直播人数" v-bind="validateInfos.number"> </div>
<a-input size="small" v-model:value="form.number" placeholder="请输入直播人数" /> <div
</a-form-item> class="upload-image upload"
<a-form-item label="直播简介" class="brief"> style="position: relative"
<a-textarea v-model:value="form.brief" :autoSize="true" class="brief-textarea" :maxlength="200" placeholder="请输入您的直播简介" /> v-show="form.fileurl.length != 0"
<span class="words-number">{{ form.brief.length }}/200</span> >
</a-form-item> <video
<a-form-item :wrapper-col="{ span: 4, offset: 0 }"> :src="form.fileurl"
<a-button @click="onSubmit">发布直播</a-button> :ref="
</a-form-item> (el) => {
</a-form> videos[0] = el;
<div class="modal-container"> }
<a-modal "
centered class="upload"
:footer="null" ></video>
:getContainer="modalNode" <!-- <a-progress type="circle" :percent="100" :width="80" style="position:absolute;right:35%"/> -->
dialogClass="modal-dialog" </div>
v-model:visible="isEntitled" </a-upload>
@cancel="hideNoticeModal" <div class="demand">
> <p class="one-line-hide">视频要求</p>
<template v-slot:closeIcon> <p class="one-line-hide">1.上传视频时间要求为30s之内</p>
<img src="@/static/images/delete.png" class="close" /> <p class="one-line-hide">2.支持文件大小100M</p>
</template> <p class="one-line-hide">
<div class="notice-container report" v-if="0"> 3.文件扩展名fivmp4文件扩展名fivmp4
<div class="title">您尚未获得直播资格</div> </p>
<div class="title sub-title">您被 学生XXX<span class="red">举报发生违规行为</span>,如有疑问点击反馈</div>
<div class="confirm-btn">意见反馈</div>
</div>
<div class="notice-container" v-else>
<div class="title">您尚未获得直播资格</div>
<div class="title sub-title">上一周/月您在平台视频点击量为 <span class="red">第24名</span>要在前 <span class="bule">20</span> 才能获得直播资格</div>
<rank-list></rank-list>
</div>
</a-modal>
</div> </div>
<nav-bottom></nav-bottom> </a-form-item>
<a-form-item label="开始时间">
<!-- <a-input
size="small"
v-model:value="form.startTime"
placeholder="请设置您的开始时间"
/> -->
<a-date-picker @change="startchange" placeholder="请设置您的开始时间" />
</a-form-item>
<a-form-item
label="直播时长"
class="duration"
v-bind="validateInfos.livetime"
>
<a-input
size="small"
v-model:value="form.livetime"
placeholder="请输入直播时间"
/>
<span class="unit">分钟</span>
</a-form-item>
<a-form-item label="直播人数" v-bind="validateInfos.livenumber">
<a-input
size="small"
v-model:value="form.livenumber"
placeholder="请输入直播人数"
/>
</a-form-item>
<a-form-item label="直播简介" class="brief">
<a-textarea
v-model:value="form.desc"
:autoSize="true"
class="brief-textarea"
:maxlength="200"
placeholder="请输入您的直播简介"
/>
<span class="words-number">{{ form.desc.length }}/200</span>
</a-form-item>
<a-form-item :wrapper-col="{ span: 4, offset: 0 }">
<a-button @click="onSubmit">发布直播</a-button>
</a-form-item>
</a-form>
<div class="modal-container">
<a-modal
centered
:footer="null"
:getContainer="modalNode"
dialogClass="modal-dialog"
v-model:visible="isEntitled"
@cancel="hideNoticeModal"
>
<template v-slot:closeIcon>
<img src="@/static/images/delete.png" class="close" />
</template>
<div class="notice-container report" v-if="0">
<div class="title">您尚未获得直播资格</div>
<div class="title sub-title">
您被 学生XXX<span class="red">举报发生违规行为</span
>,如有疑问点击反馈
</div>
<div class="confirm-btn">意见反馈</div>
</div>
<div class="notice-container" v-else>
<div class="title">您尚未获得直播资格</div>
<div class="title sub-title">
上一周/月您在平台视频点击量为
<span class="red">第24名</span>要在前
<span class="bule">20</span> 才能获得直播资格
</div>
<rank-list></rank-list>
</div>
</a-modal>
</div> </div>
<nav-bottom></nav-bottom>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, Ref, ref, toRaw } from 'vue'; import {
import { PlaySquareOutlined, PlusOutlined } from '@ant-design/icons-vue'; defineComponent,
import { useForm } from '@ant-design-vue/use'; onBeforeUpdate,
import NavBottom from '@/components/NavBottom.vue'; onMounted,
import RankList from './RankList.vue'; reactive,
import { previewCover } from '@/utils/common'; Ref,
import { FromSend, ImgInfo } from "@/types/index" ref,
toRaw,
} from "vue";
import { PlaySquareOutlined, PlusOutlined } from "@ant-design/icons-vue";
import { useForm } from "@ant-design-vue/use";
import NavBottom from "@/components/NavBottom.vue";
import RankList from "./RankList.vue";
import { previewCover } from "@/utils/common";
import { FromSend, ImgInfo } from "@/types/index";
import { uploadflie } from "@/utils/vod";
import { liveadd } from "@/api";
export default defineComponent({ export default defineComponent({
name: 'ReleaseWebcast', name: "ReleaseWebcast",
components: { components: {
PlaySquareOutlined, PlaySquareOutlined,
PlusOutlined, PlusOutlined,
NavBottom, NavBottom,
RankList, RankList,
}, },
setup() { setup() {
// //
const form = reactive({ const form = reactive({
title: '', title: "",
cover: '', img: "",
introduction: '', fileid: "",
startTime: '', fileurl: "",
duration: '', fileduration: 0,
number: '', dateline: "",
brief: '', livetime: "",
}); livenumber: "",
/** desc: "",
* 验证直播时间 });
*/
async function validateDuration (rule: unknown, value: number): Promise<string | void> {
if (value < 30 || value > 120) {
return Promise.reject('*最短30min 最长120min');
} else {
return Promise.resolve();
}
}
/**
* 验证直播人数
*/
const validateNumber = async (rule: unknown, value: number): Promise<string | void> => {
if (value < 1 || value > 4) {
return Promise.reject('**最少1人最多4人');
} else {
return Promise.resolve();
}
};
//
const rules = reactive({
duration: [
{
validator: validateDuration,
trigger: 'change',
},
],
number: [
{
validator: validateNumber,
trigger: 'change',
},
],
});
// const uploadprogress: Ref<number> = ref(0);
const viewCover: Ref<boolean> = ref(false); const uploadpicprogress: Ref<number> = ref(0);
const previewImage: Ref<string> = ref(''); const videofile = ref<File>();
const videos = ref<Array<any>>([]);
/** /**
* 封面改变触发事件 * 验证直播时间
*/ */
async function validateaLivetime(
function coverChange(info: ImgInfo): void { rule: unknown,
// console.log(info); value: number
// ): Promise<string | void> {
previewCover(info.file).then(url => previewImage.value = url); console.log(value);
viewCover.value = true; if (value < 30 || value > 120) {
// form.cover = fileList; return Promise.reject("*最短30min 最长120min");
} } else {
return Promise.resolve();
const { resetFields, validate, validateInfos } = useForm(form, rules); }
/**
* 表单提交
*/
const onSubmit = (e: FromSend) => {
e.preventDefault();
validate().then(() => {
console.log(toRaw(form));
}).catch((err: unknown) => {
console.log('error', err);
});
};
const isEntitled: Ref<boolean> = ref(true);
/**
* 隐藏无资格提示
*/
function hideNoticeModal(): void {
isEntitled.value = false;
}
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
modalNode: () => document.getElementsByClassName('modal-container')[0],
validateInfos,
resetFields,
viewCover,
previewImage,
coverChange,
form,
onSubmit,
isEntitled,
hideNoticeModal,
}
} }
}) /**
* 验证直播人数
*/
const validateLivenumber = async (
rule: unknown,
value: number
): Promise<string | void> => {
console.log(value);
if (value < 1 || value > 4) {
return Promise.reject("**最少1人最多4人");
} else {
return Promise.resolve();
}
};
//
const rules = reactive({
livetime: [
{
validator: validateaLivetime,
trigger: "change",
},
],
livenumber: [
{
validator: validateLivenumber,
trigger: "change",
},
],
});
//
const viewCover: Ref<boolean> = ref(false);
const previewImage: Ref<string> = ref("");
/**
* 封面改变触发事件
*/
function coverChange(info: ImgInfo): void {
// console.log(info);
//
previewCover(info.file).then((url) => (previewImage.value = url));
viewCover.value = true;
// form.cover = fileList;
}
const { resetFields, validate, validateInfos } = useForm(form, rules);
/**
* 表单提交
*/
const subdata = reactive({
title: "",
img: "",
fileid: "",
fileurl: "",
fileduration: "",
dateline: "",
livetime: "",
livenumber: "",
desc: "",
});
const onSubmit = (e: FromSend) => {
e.preventDefault();
validate()
.then(() => {
// console.log(toRaw(form),111);
let subdata = toRaw(form);
// subdata.fileid=picinfo.
console.log(subdata);
liveadd(subdata);
})
.catch((err: unknown) => {
console.log("error", err);
});
};
const isEntitled: Ref<boolean> = ref(true);
/**
* 隐藏无资格提示
*/
function hideNoticeModal(): void {
isEntitled.value = false;
}
/**
* 开始时间设置
*/
function startchange(e: string): void {
let month=new Date(e).getMonth()+1
console.log(new Date(e).getFullYear()+"-"+month+'-'+new Date(e).getDate())
form.dateline =
new Date(e).getFullYear() +
"-" +
month +
"-" +
new Date(e).getDate();
}
/**
* 上传文件
*/
const videoinfo = reactive({
fileId: "",
url: "",
});
const picinfo = reactive({
fileId: "",
url: "",
});
interface AntUpload {
action: string;
data: unknown;
file: File;
}
async function uploads(file: AntUpload) {
console.log(file);
videofile.value = file.file;
videos.value[0].addEventListener("durationchange", () => {
console.log(videos.value[0].duration);
form.fileduration = videos.value[0].duration;
});
let res = await uploadflie(file.file, (info: any) => {
console.log(info);
uploadprogress.value = info.percent.toFixed(2) * 100;
});
console.log(res);
form.fileid = res.fileId;
form.fileurl = res.video.url;
}
async function uploadspic(file: AntUpload) {
let res = await uploadflie(file.file, (info: any) => {
console.log(info);
uploadpicprogress.value = info.percent.toFixed(2) * 100;
});
console.log(res);
// picinfo.fileId=res.fileId
// picinfo.url=res.video.url
form.img = res.video.url;
}
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
modalNode: () => document.getElementsByClassName("modal-container")[0],
validateInfos,
resetFields,
viewCover,
previewImage,
coverChange,
form,
onSubmit,
isEntitled,
hideNoticeModal,
uploads,
uploadprogress,
videoinfo,
uploadspic,
uploadpicprogress,
picinfo,
startchange,
videofile,
videos,
};
},
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.webcast { .webcast {
width: 100%; width: 100%;
min-width: 700px; min-width: 700px;
background-color: #ffffff; background-color: #ffffff;
padding: 46px; padding: 46px;
border-radius: 17px; border-radius: 17px;
position: relative; position: relative;
::v-deep(.ant-form) { ::v-deep(.ant-form) {
.title { .title {
font-size: 12px; font-size: 12px;
font-weight: bold;
color: #111111;
margin-bottom: 28px;
}
.ant-row {
.ant-form-item-label {
width: 60px;
margin: 0 30px 0 17px;
> label {
font-size: 12px;
font-weight: 500;
color: #808080;
&::after {
content: "";
}
}
}
.upload {
width: 171px;
height: 96px;
}
.upload-image {
width: 171px;
height: 96px;
border: 1px solid #dcdfe0;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 17px;
}
.ant-input {
width: 171px;
padding: 6px 11px;
border-radius: 3px;
border: 1px solid #dcdfe0;
font-size: 11px;
color: #3f3f3f;
&::-webkit-input-placeholder {
font-size: 12px;
color: #808080;
}
}
.ant-select {
font-size: 12px;
}
.ant-select-dropdown {
font-size: 12px;
}
.ant-form-explain {
font-size: 10px;
font-weight: 500;
color: #d22d2e;
}
.ant-upload-list {
display: none;
}
.ant-btn {
padding: 0;
width: 63px;
height: 23px;
background: #08ae98;
border-radius: 3px;
font-size: 10px;
font-weight: 500;
color: #ffffff;
}
}
.item-cover {
.preview-image {
width: 171px;
height: 96px;
}
}
.video-introduction {
.ant-form-item-control-wrapper {
.ant-form-item-children {
display: flex;
align-items: center;
.demand {
line-height: 17px;
font-size: 10px;
font-weight: 500;
color: #808080;
width: 134px;
> p {
margin: 0;
}
}
}
}
}
.duration {
.unit {
margin-left: 18px;
font-size: 12px;
font-weight: 500;
color: #808080;
}
}
.brief {
position: relative;
.ant-input {
width: 359px;
}
.brief-textarea {
min-height: 85px;
padding-bottom: 30px;
}
.words-number {
position: absolute;
right: 11px;
bottom: -11px;
font-size: 11px;
font-weight: 500;
color: #7f7f7f;
user-select: none;
}
}
}
.modal-container {
::v-deep(.modal-dialog) {
.close {
width: 14px;
height: 14px;
}
.ant-modal-content {
box-sizing: border-box;
padding: 25px 30px;
width: 569px;
background: #ffffff;
box-shadow: 0px 4px 6px 0px rgba(102, 102, 102, 0.07);
border-radius: 28px;
.notice-container {
.title {
font-size: 11px;
font-weight: bold; font-weight: bold;
color: #111111; color: #111111;
margin-bottom: 28px; margin-bottom: 16px;
}
.sub-title {
.red {
color: #d12c2d;
}
.bule {
color: #0dbba3;
}
}
.confirm-btn {
display: inline-block;
background: #07ad97;
border-radius: 2px;
font-size: 9px;
font-weight: 500;
color: #ffffff;
text-align: center;
cursor: pointer;
user-select: none;
height: 22px;
line-height: 22px;
padding: 0 17px;
}
} }
.ant-row { .report {
.ant-form-item-label { .sub-title {
width: 60px; margin-bottom: 50px;
margin: 0 30px 0 17px; }
> label {
font-size: 12px;
font-weight: 500;
color: #808080;
&::after {
content: '';
}
}
}
.upload-image {
width: 171px;
height: 96px;
border: 1px solid #DCDFE0;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 17px;
}
.ant-input {
width: 171px;
padding: 6px 11px;
border-radius: 3px;
border: 1px solid #DCDFE0;
font-size: 11px;
color: #3F3F3F;
&::-webkit-input-placeholder{
font-size: 12px;
color: #808080;
}
}
.ant-select {
font-size: 12px;
}
.ant-select-dropdown {
font-size: 12px;
}
.ant-form-explain {
font-size: 10px;
font-weight: 500;
color: #D22D2E;
}
.ant-upload-list {
display: none;
}
.ant-btn {
padding: 0;
width: 63px;
height: 23px;
background: #08AE98;
border-radius: 3px;
font-size: 10px;
font-weight: 500;
color: #FFFFFF;
}
}
.item-cover {
.preview-image {
width: 171px;
height: 96px;
}
}
.video-introduction {
.ant-form-item-control-wrapper {
.ant-form-item-children {
display: flex;
align-items: center;
.demand {
line-height: 17px;
font-size: 10px;
font-weight: 500;
color: #808080;
width: 134px;
> p {
margin: 0;
}
}
}
}
}
.duration {
.unit {
margin-left: 18px;
font-size: 12px;
font-weight: 500;
color: #808080;
}
}
.brief {
position: relative;
.ant-input {
width: 359px;
}
.brief-textarea {
min-height: 85px;
padding-bottom: 30px;
}
.words-number {
position: absolute;
right: 11px;
bottom: -11px;
font-size: 11px;
font-weight: 500;
color: #7F7F7F;
user-select: none;
}
}
}
.modal-container {
::v-deep(.modal-dialog) {
.close {
width: 14px;
height: 14px;
}
.ant-modal-content {
box-sizing: border-box;
padding: 25px 30px;
width: 569px;
background: #FFFFFF;
box-shadow: 0px 4px 6px 0px rgba(102, 102, 102, 0.07);
border-radius: 28px;
.notice-container {
.title {
font-size: 11px;
font-weight: bold;
color: #111111;
margin-bottom: 16px;
}
.sub-title {
.red {
color: #D12C2D;
}
.bule {
color: #0DBBA3;
}
}
.confirm-btn {
display: inline-block;
background: #07AD97;
border-radius: 2px;
font-size: 9px;
font-weight: 500;
color: #FFFFFF;
text-align: center;
cursor: pointer;
user-select: none;
height: 22px;
line-height: 22px;
padding: 0 17px;
}
}
.report {
.sub-title {
margin-bottom: 50px;
}
}
}
} }
}
} }
}
} }
</style> </style>

View File

@ -12,16 +12,7 @@
</div> </div>
</div> </div>
<div class="list" v-if="tabindex==1"> <div class="list" v-if="tabindex==1">
<LiveItem :type="2"></LiveItem> <LiveItem :type="2" v-for="(i,j) in livelist" :key="j" :img="i.img" :title="i.title" :score="i.score" :date="i.starttime" :takehour="i.vodduration" :livenum="i.livenumber" :status="i.livestatus"></LiveItem>
<LiveItem :type="2"></LiveItem>
<LiveItem :type="2"></LiveItem>
<LiveItem></LiveItem>
<LiveItem></LiveItem>
<LiveItem></LiveItem>
<LiveItem></LiveItem>
<LiveItem></LiveItem>
<LiveItem></LiveItem>
<LiveItem></LiveItem>
</div> </div>
<div class="list" v-if="tabindex==2"> <div class="list" v-if="tabindex==2">
@ -144,24 +135,29 @@
} }
</style> </style>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref } from "vue"; import { defineComponent, onMounted, ref } from "vue";
import LiveItem from "@/components/LiveItem.vue"; import LiveItem from "@/components/LiveItem.vue";
import { getlivelist } from '@/api'; import { getlivelist } from '@/api';
import { LiveList } from '@/types';
export default defineComponent({ export default defineComponent({
components: { components: {
LiveItem, LiveItem,
}, },
setup() { setup() {
const page = ref(6); const page = ref(1);
const tabindex = ref(1); const tabindex = ref(1);
getlivelist() const livelist=ref<Array<LiveList>>()
onMounted(async ()=>{
livelist.value= await getlivelist()
})
function tabchange(e: number): void { function tabchange(e: number): void {
tabindex.value=e tabindex.value=e
} }
return { return {
page, page,
tabindex, tabindex,
tabchange tabchange,
livelist
}; };
}, },
}); });