123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- <template>
- <view class="play-container">
- <u-loading-page :loading="loading" :bg-color="$colors.bgColor" :color="$colors.primaryColor"
- :loading-color="$colors.primaryColor" />
- <template v-if="!loading">
- <!-- 剧集按钮-->
- <episode-buttons :episode="episode" :current-episode="currentEpisode" @change="handleCollectAndFavChange" />
- <!--视频播放-->
- <view class="video-box main-center cross-center" :style="{zIndex: isPlaying ? 0 : 998}">
- <!--视频容器-->
- <swiper class="swiper" circular :vertical="true" :current="swiperCurrent" @change="handleSwiperChancge"
- @animationfinish="handleSwiperAnimationFinish">
- <swiper-item v-for="(item, index) in swiperEpisode" :key="index" class="swiper-item">
- <!-- #ifdef MP-TOUTIAO | MP-WEIXIN-->
- <!-- 控制按钮 - 播放 -->
- <view v-if="!item.isPlaying" class="play-layer main-center cross-center" @tap="handlePlay(item)">
- <view class="icon">
- <u-icon name="play-right-fill" size="100rpx" :color="$colors.defaultColor" />
- </view>
- </view>
- <!-- 控制按钮 - 暂停 -->
- <view v-if="item.isPlaying" class="pause-layer" @tap="handlePause(item, true)" />
- <!-- #endif-->
- <video v-if="Object.keys(item).length" :autoplay="(index==='current'&&isFirstLoad)?'autoplay':false"
- :id="`video${index}`" :poster="episode.cover_img" :src="item.url" :style="{
- width:'100%',
- height: 'calc(100vh - 130rpx)',
- zIndex: 0
- }" :show-play-btn="video.playBtn" :show-center-play-btn="video.playBtn"
- :show-fullscreen-btn="video.fullscreenBtn" :controls="video.controls" :show-progress="video.progress"
- object-fit="contain" @timeupdate="timeupdate" @ended="ended" @play="play($event,item)" />
- </swiper-item>
- </swiper>
- </view>
- <!--底部-->
- <episode-part :episode="episode" :is-playing="isPlaying" :buy-record="buyRecord" :current-episode="currentEpisode"
- @selectEpisode="handleSelectEpisode" />
- <!--充值-->
- <recharge :show.sync="rechargeShow" type="play" mode="bottom" :episode="episode" :list="currentEpisode" />
- </template>
- </view>
- </template>
- <script>
- import {
- mapState
- } from 'vuex'
- import Recharge from '../../components/Recharge/index'
- import EpisodeButtons from './components/EpisodeButtons'
- import EpisodePart from './components/EpisodePart'
- export default {
- name: 'Play',
- components: {
- EpisodePart,
- EpisodeButtons,
- Recharge
- },
- data() {
- return {
- isFirstLoad: true, //是否首次播放
- id: null, // 短剧ID
- listId: null, // 剧集ID
- isPlaying: false, // 是否播放
- progress: 0, // 进度条
- episode: {}, // 短剧信息
- lists: [], // 剧集信息
- loading: false, // 数据加载
- video: { // 视频配置
- controls: true,
- progress: true,
- fullscreenBtn: false,
- playBtn: false,
- // #ifdef MP-KUAISHOU | MP-TOUTIAO
- duration: 450,
- // #endif
- // #ifdef MP-WEIXIN
- duration: 500
- // #endif
- },
- buyRecord: [], // 购买记录
- rechargeShow: false, // 显示充值
- swiperCurrent: 1, // 当前滚动
- currentEpisode: {}, // 当前播放剧集
- swiperEpisode: { // swiper 剧集
- prev: {},
- current: {},
- next: {}
- },
- indexArr: {
- 'prev': 0,
- 'current': 1,
- 'next': 2
- }
- }
- },
- computed: {
- ...mapState({
- userInfo: seate => seate.user.info
- }),
- videoContext() {
- const indexArr = ['prev', 'current', 'next']
- const swiperKey = indexArr[this.swiperCurrent]
- return uni.createVideoContext(`video${swiperKey}`, this)
- }
- },
- watch: {
- // 进度条
- progress(val) {
- if (val >= 100) {
- const indexArr = ['prev', 'current', 'next']
- const len = this.lists.length
- const swiperKey = indexArr[this.swiperCurrent]
- if (this.swiperEpisode[swiperKey].sort === this.lists[len - 1].sort) {
- this.$u.toast('已全部播放完成')
- return 100
- }
- // 切换
- switch (this.swiperCurrent) {
- case 0:
- this.swiperCurrent = 1
- break
- case 1:
- this.swiperCurrent = 2
- break
- case 2:
- this.swiperCurrent = 0
- break
- }
- this.$forceUpdate()
- }
- },
- swiperCurrent(val) {
- const indexArr = ['prev', 'current', 'next']
- const swiperKey = indexArr[val]
- const dataIndex = this.lists.findIndex(val => {
- return this.swiperEpisode[swiperKey].sort === val.sort
- })
- const len = this.lists.length
- let prevIndex, currentIndex, nextIndex
- switch (swiperKey) {
- case 'prev':
- currentIndex = dataIndex + 1 >= len ? 0 : dataIndex + 1
- nextIndex = dataIndex - 1 < 0 ? len - 1 : dataIndex - 1
- this.swiperEpisode.current = this.lists[currentIndex]
- this.swiperEpisode.next = this.lists[nextIndex]
- break
- case 'current':
- prevIndex = dataIndex - 1 < 0 ? len - 1 : dataIndex - 1
- nextIndex = dataIndex + 1 >= len ? 0 : dataIndex + 1
- this.swiperEpisode.prev = this.lists[prevIndex]
- this.swiperEpisode.next = this.lists[nextIndex]
- break
- case 'next':
- prevIndex = dataIndex + 1 >= len ? 0 : dataIndex + 1
- currentIndex = dataIndex - 1 < 0 ? len - 1 : dataIndex - 1
- this.swiperEpisode.current = this.lists[currentIndex]
- this.swiperEpisode.prev = this.lists[prevIndex]
- break
- }
- // 暂停其他
- this.handlePause(this.currentEpisode, false)
- // 当前播放剧集
- this.currentEpisode = this.swiperEpisode[swiperKey]
- // 播放
- this.handlePlay(this.currentEpisode)
- },
- currentEpisode(val) {
- console.log('-->当前剧集', val.sort)
- }
- },
- methods: {
- // 播放进度
- timeupdate({
- detail
- }) {
- // currentTime, duration
- if (detail.duration) {
- this.progress = (detail.currentTime / detail.duration * 100).toFixed(2)
- }
- },
- ended() {
- // #ifdef MP-KUAISHOU
- this.progress = 100
- // #endif
- },
- play(e, item) {
- console.log('-->data', e, item)
- // #ifdef MP-KUAISHOU
- this.handlePlay(item)
- // #endif
- },
- // 播放
- handlePlay(item) {
- this.currentEpisode = item
- // 检查是否购买
- if (!this.checkBeforePlay(item)) {
- // 余额是否购买
- if (!this.checkOverage(item)) {
- // #ifdef MP-KUAISHOU
- // 如果没有购买,那把视频链接设置为空 停止播放,使用 pause 和 stop 在真机上不生效 只能采用这种方式
- // item.url = ''//让对应的视频停止播放==========》
- this.videoContext.stop();
- // #endif
- this.rechargeShow = true
- return
- }
- // 余额足够 直接购买
- this.handleBuy()
- return
- }
- this.isPlaying = true
- item.isPlaying = true
- // #ifdef MP-KUAISHOU
- item.url = item.src
- this.$forceUpdate()
- setTimeout(() => {
- this.isFirstLoad || this.videoContext.play(); //当滑动的时候自动播放
- // const query = uni.createSelectorQuery().in(this);
- // let videoDom=query.select('#videocurrent');
- // console.log('视频播放器:',videoDom.node())
- // videoDom.node().play();
- }, 1000)
- // #endif
- // #ifdef MP-TOUTIAO | MP-WEIXIN
- this.videoContext.play()
- // #endif
- this.progress = 0
- this.watched(this.id, this.currentEpisode.id)
- },
- // 暂停
- handlePause(item, isAll = false) {
- if (!this.isPlaying) return
- item.isPlaying = false
- this.isPlaying = false
- // 展厅其他的
- const indexArr = ['prev', 'current', 'next']
- const swiperKey = indexArr[this.swiperCurrent]
- indexArr.forEach(obj => {
- if (swiperKey !== obj || isAll) {
- const videoContext = uni.createVideoContext(`video${obj}`, this)
- videoContext.pause()
- }
- })
- },
- // 选择剧集
- handleSelectEpisode(index) {
- // 暂停上一个
- this.handlePause(this.currentEpisode, true)
- const item = this.lists[index]
- // 重置SwiperEpisode数据 切换播放
- this.swiperCurrent = 1
- this.initSwiperEpisode(item.id)
- },
- // 当前剧集购买记录
- async getBuyRecord() {
- await this.$api.user.episode.buyRecord(this.id).then(res => {
- this.buyRecord = res.data
- })
- },
- // 购买剧集
- async handleBuy() {
- await this.$api.user.episode.buyHandle(this.id, this.currentEpisode.id).then(async res => {
- this.$hideLoading()
- if (typeof res.data.overage !== 'undefined') {
- this.rechargeShow = true
- } else {
- this.$u.toast('购买成功')
- await this.getBuyRecord()
- this.handlePlay(this.currentEpisode)
- this.$api.user.info().then(res => {
- this.$store.dispatch('user/info', res.data)
- })
- }
- }).catch(() => {
- this.$hideLoading()
- })
- },
- // 滚动 Swiper
- handleSwiperChancge({
- detail
- }) {
- this.isFirstLoad = false;
- // this.swiperCurrent = detail.current
- },
- handleSwiperAnimationFinish({
- detail
- }) {
- this.swiperCurrent = detail.current //注释掉尝试-------》
- },
- // 播放前检查剧集是否购买/免费
- checkBeforePlay(item) {
- // 剧集免费 不免费已购买 VIP观看是VIP
- if (item.is_free) {
- return true
- }
- if (!item.is_free && this.buyRecord.indexOf(item.id) !== -1) {
- return true
- }
- if (this.episode.is_vip_watch && this.userInfo.info.is_vip) {
- return true
- }
- return false
- },
- // 检查余额是否足够支付
- checkOverage(item) {
- return this.userInfo.info.integral >= item.sale_price
- },
- // 记录观看记录
- watched(id, list_id) {
- this.$api.user.episode.watched(id, list_id).then(res => {
- })
- },
- // 分享
- handleShared(id) {
- console.log('-->handleShared success')
- this.$api.episode.shared(id).then(res => {
- this.episode.share_count += 1
- })
- },
- handleCollectAndFavChange(data) {
- if (data.type === 'collect') {
- this.episode.user_collect_count += data.num
- } else {
- // this.episode.user_favorite_count += data.num
- }
- },
- // // 初始化 Swiper 剧集
- initSwiperEpisode(listId) {
- let currentIndex = 0
- if (listId) {
- currentIndex = this.lists.findIndex(obj => {
- return parseInt(listId) === parseInt(obj.id)
- })
- }
- let prevIndex = currentIndex - 1
- let nextIndex = currentIndex + 1
- const len = this.lists.length
- if (parseInt(listId) === 0 || prevIndex < 0) {
- prevIndex = len - 1
- }
- //
- if (nextIndex >= len) {
- nextIndex = 0
- }
- this.swiperEpisode = {
- prev: this.lists[prevIndex],
- current: this.lists[currentIndex],
- next: this.lists[nextIndex]
- }
- console.log('-->swiper data', JSON.stringify(this.swiperEpisode))
- this.currentEpisode = this.lists[currentIndex]
- console.log('-->currentEpisode', this.currentEpisode)
- this.$nextTick(() => {
- this.handlePlay(this.currentEpisode)
- })
- },
- // 获取剧集详情
- getEpisode() {
- this.loading = true
- this.$api.episode.detail(this.id).then(res => {
- this.loading = false
- this.episode = res.data
- uni.setNavigationBarTitle({
- title: this.episode.name + (this.episode.status === 0 ? ' | 更新中' : '已完结')
- })
- this.episode.lists.forEach((obj, index) => {
- obj.isPlaying = false
- obj.index = index
- obj.progress = 0
- obj.src = obj.url
- })
- this.lists = this.episode.lists
- // 初始化 Swiper 剧集
- this.initSwiperEpisode(this.listId)
- })
- }
- },
- async onLoad(options) {
- this.id = options.id
- this.listId = options?.list_id
- this.listId = this.listId ? this.listId : 0
- await this.getBuyRecord()
- this.getEpisode()
- },
- // 分享
- onShareAppMessage(res) {
- if (res.from === 'button') { // 来自页面内分享按钮
- console.log(res.target)
- }
- let options = {
- title: '',
- path: `/pages/episode/play?id=${this.id}&user_id=${this.userInfo.user_id}`
- }
- if (this.episode) {
- // 没有success 回调 只要点击分享了就默认成功
- this.handleShared(this.id)
- options = {
- title: this.episode.name,
- path: `/pages/episode/play?id=${this.id}&user_id=${this.userInfo.user_id}`,
- imageUrl: this.episode.cover_img,
- desc: this.episode.name
- }
- }
- return options
- }
- }
- </script>
- <style lang="scss" scoped>
- .play-container {
- font-size: 28rpx;
- .video-box {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- .play-layer {
- position: fixed;
- top: 0;
- left: 0;
- // #ifdef MP-KUAISHOU | MP-WEIXIN
- bottom: 240rpx;
- // #endif
- // #ifdef MP-TOUTIAO
- bottom: 360rpx;
- // #endif
- right: 0;
- background: transparent;
- z-index: 999;
- .icon {
- position: absolute;
- top: 50%;
- transform: translate(2px, 63%);
- }
- }
- .pause-layer {
- position: absolute;
- top: 0;
- left: 0;
- // #ifdef MP-KUAISHOU | MP-WEIXIN
- bottom: 240rpx;
- // #endif
- // #ifdef MP-TOUTIAO
- bottom: 360rpx;
- // #endif
- right: 0;
- background: transparent;
- z-index: 99;
- }
- .swiper {
- width: 100%;
- height: 100vh;
- position: relative;
- z-index: 99;
- .swiper-item {
- width: 100%;
- height: 100vh !important;
- }
- }
- .progress-container {
- width: 93vw;
- background: #fff;
- height: 10rpx;
- position: fixed;
- z-index: 100;
- bottom: 160rpx;
- .progress {
- height: 10rpx;
- background: linear-gradient(270deg, #6EEBE8 0%, #FF74B9 100%);
- }
- }
- }
- }
- </style>
|