You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
zhishifufei_uniapp/pages/special/source_detail.vue

911 lines
20 KiB

<template>
<BaseContainer>
<NavBar title="素材详情" />
<view class="source-detail-page" v-if="source">
<view class="player-box">
<view v-if="source.type === 3">
<video id="myVideo" @loadedmetadata="handleReady" @ended="handleEnded" @timeupdate="handleTimeupdateVideo"
class="player-self" :poster="source.image" :src="source.link"></video>
</view>
<view v-show="tryShow" class="try">
<i class="iconfont iconbofang"></i>免费试看
</view>
<image :src="source.image" class="cover" mode="aspectFill" />
</view>
<view class="title-wrap">
<view class="title">{{ source.title }}</view>
<view class="wrap">
<view class="learn">{{ source.play_count + 1 }}次学习</view>
<view v-if="isWeiXin" class="share" @click="share = true">
<view class="iconfont iconfenxiang"></view>
分享
</view>
</view>
</view>
<view v-if="source.type === 2" class="audio-player">
<view v-if="!(!source.videoId && !source.link)" class="control">
<view @click="toggleTask">
<i class="iconfont icon" :class="isPause ? 'iconbofang' : 'iconzanting'"></i>
</view>
<view class="timeline" @touchmove="moveTask" @touchend="moveEndTask">
<view>{{ currentTime | formatTime(duration) }}</view>
<view class="progress">
<view :style="{ width: taskRange + '%' }" class="inner">
<view class="thumb"></view>
</view>
</view>
<view>{{ duration | formatTime }} </view>
</view>
</view>
</view>
<view class="main">
<view class="title">详情</view>
<mp-html class="wrap" container-style="padding: 30rpx;background: #ffffff;"
:content="source.type == 1 && source.is_try ? source.try_content : source.detail"></mp-html>
</view>
<view class="third">
<view class="group flex">
<view class="btn flex flex-center-y flex-column" @click="goPage(1)">
<image :src="getImgPath('/wap/first/zsff/images/special01.png')" />
<view>首页</view>
</view>
<!-- 抖音客服 -->
<view class="btn flex flex-center-y flex-column" v-if="TOUTIAO_STATUS">
<button class="im" open-type="im" :data-im-id="source.d_im" bindim="imCallback" binderror="onimError">
<image :src="getImgPath('/wap/first/zsff/images/special02.png')" />
客服</button>
</view>
<!-- 系统客服 -->
<view class="btn flex flex-center-y flex-column" @click="goPage(2)" v-else>
<image :src="getImgPath('/wap/first/zsff/images/special02.png')" />
<view>客服</view>
</view>
</view>
<view v-if="course.length > 0" @click="relatedCourses" class="submit-btn flex flex-center">相关课程</view>
<view v-else class="submit-btn flex flex-center" @click="relatedCourses">更多课程</view>
</view>
<image v-show="share" class="share-mask" :src="getImgPath('/wap/first/zsff/images/share-info.png')"
@touchmove.prevent @click="share = false" />
<view :class="{ mask: dialog }" @touchmove.prevent @click="dialog = false"></view>
<view class="dialog" :class="{ active: dialog }" @touchmove.prevent>
<view class="ul" v-if="course.length">
<view class="li" v-for="item in course" :key="item.id">
<navigator :url="`/pages/special/details?id=${item.id}`">
<view class="figure">
<image :src="item.image" />
<text>{{ item.type_name }}</text>
</view>
<view class="figcaption">
<view class="title">{{ item.title }}</view>
<view class="mark">
<text v-for="itm in item.label">{{ itm }}</text>
</view>
<view class="info">
<view class="money">
¥<text>{{ item.money }}</text>
</view>
<view class="lesson">共{{ item.count }}节</view>
<view class="learn">{{ item.record }}次学习</view>
</view>
</view>
</navigator>
</view>
</view>
<image v-else class="empty" :src="getImgPath('/wap/first/zsff/images/no_data_available.png')" />
</view>
</view>
</BaseContainer>
</template>
<script>
import {
getSourceDetail,
getSpecialRelatedCourses,
getVideoPlayCredentials,
} from "@/api/special";
import mpHtml from "mp-html/dist/uni-app/components/mp-html/mp-html.vue";
import dayjs from "dayjs";
import { CUSTOMER_DETAIL_TYPE, CUSTOMER_SUPPORT_TYPE } from "@/constants/customer-type";
export default {
filters: {
formatTime(time, sibling) {
let duration = dayjs.duration(time * 1000);
let hours = duration.hours();
let siblingHours = sibling ? dayjs.duration(sibling * 1000).hours() : 0;
return dayjs({
h: hours,
m: duration.minutes(),
s: duration.seconds(),
}).format((hours || siblingHours ? "HH:" : "") + "mm:ss");
},
},
components: {
mpHtml,
},
computed: {
taskRange: function () {
return Math.floor(this.currentTime / this.duration * 100);
}
},
data() {
const { screenHeight: height } = this.$util.getSystemInfo();
return {
currentTime: 0,
duration: 0,
id: "",
source: null,
course: [],
isPause: true,
dialog: false,
appear: true,
share: false,
width: 0,
height: height - 400 + "rpx",
track: null,
audio: null,
paused: true,
aliplayer: null,
isWeiXin: false,
tryShow: true,
player: null,
TOUTIAO_STATUS:false
};
},
onLoad({ id }) {
this.id = id;
this.getSourceDetail();
this.getRelateCourse();
/* #ifdef MP-TOUTIAO */
this.TOUTIAO_STATUS = true;
/* #endif */
},
onUnload() {
this.aliplayer.dispose();
},
methods: {
relatedCourses() {
if (this.course.length > 0) {
this.dialog = true;
} else {
uni.navigateTo({
url: "/pages/course/special_cate",
});
}
},
async handlePlayVideo() {
if (this.source.videoId) {
uni.showLoading({ mask: true });
try {
const { msg } = await getVideoPlayCredentials(this.source.videoId, 2);
uni.hideLoading();
uni.request({
url: msg,
dataType: "json",
success: (res) => {
if (res.status === 200) {
this.handleCreatePlayer(res.data.PlayAuth);
} else {
this.$util.showMsg(res.Message);
}
},
fail: (err) => {
this.$util.showMsg(err.msg);
},
});
} catch (err) {
uni.hideLoading();
this.$util.showMsg(err.msg);
}
} else {
}
},
goPage(value) {
switch (value) {
case 1:
uni.switchTab({
url: "/pages/index/index",
});
break;
case 2:
this.$util.goSupport(CUSTOMER_DETAIL_TYPE.GOOD, CUSTOMER_SUPPORT_TYPE.SOURCE, this.id);
break;
}
},
// 创建播放器
createPlayer() {
this.player = uni.createVideoContext("myVideo");
},
createAudioPlayer() {
if (this.player) {
this.player.stop();
this.player = null;
}
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = false;
innerAudioContext.src = this.source.link;
innerAudioContext.onCanplay(() => {
let intervalID = setInterval(() => {
if (innerAudioContext.duration !== 0) {
clearInterval(intervalID);
this.duration = innerAudioContext.duration;
}
}, 100);
});
innerAudioContext.onEnded(() => {
this.handleEnded();
});
innerAudioContext.onTimeUpdate(() => {
this.handleTimeupdate();
});
this.player = innerAudioContext;
},
handleEnded() {
},
handleTimeupdate() {
this.currentTime = this.player.currentTime;
var floorTime = Math.floor(this.currentTime);
if (floorTime && floorTime !== this.floorTime && !(floorTime % 10)) {
this.floorTime = floorTime;
}
},
onUnload() {
if(!this.player) return;
this.player.pause()
},
// 播放/暂停音频
toggleTask: function () {
this.isPause = !this.isPause;
this.isPause ? this.player.pause() : this.player.play();
},
// 滑动音频
moveTask: function (event) {
if (!this.player || !this.player.paused) {
this.isPause = true;
this.player.pause();
}
this.$util.getClientRect(".progress").then(({ left, width }) => {
let range = Math.floor(((event.touches[0].pageX - left) / width) * 100);
if (range > 100) {
range = 100;
}
this.audioRange = range;
});
},
// 滑动音频停止
moveEndTask: function () {
this.player.seek((this.duration * this.audioRange) / 100);
if (this.player.paused) {
this.isPause = false
this.player.play();
}
},
// 获取素材
async getSourceDetail() {
uni.showLoading({ mask: true });
try {
const { data } = await getSourceDetail(this.id);
uni.hideLoading();
this.source = data;
if (this.source.type === 2) {
this.createAudioPlayer();
} else if (this.source.type === 3) {
this.createPlayer();
}
} catch (err) {
uni.hideLoading();
this.$util.showMsg(err.msg);
}
},
// 获取关联课程
async getRelateCourse() {
uni.showLoading({ mask: true });
try {
const { data } = await getSpecialRelatedCourses(this.id);
uni.hideLoading();
const course = data;
course.forEach((item) => {
switch (item.type) {
case 1:
item.type_name = "图文";
break;
case 2:
item.type_name = "音频";
break;
default:
item.type_name = "视频";
break;
}
});
this.course = course;
} catch (err) {
uni.hideLoading();
this.$util.showMsg(err.msg);
}
},
},
};
</script>
<style>
.uni-video-video {
object-fit: cover !important;
}
</style>
<style scoped lang="scss">
p {
box-sizing: border-box;
}
.prism-player video {
object-fit: cover;
}
.source-detail-page .handle-wrap svg {
color: #2c8eff;
}
.player-box {
position: relative;
}
.player-box .try {
position: absolute;
display: flex;
right: 30rpx;
bottom: 30rpx;
z-index: 13;
padding: 11rpx 16rpx 11rpx 14rpx;
border-radius: 23rpx;
background-color: rgba(0, 0, 0, 0.6);
font-size: 22rpx;
line-height: 24rpx;
color: #ffffff;
}
.player-box .try .iconfont {
margin-right: 8rpx;
vertical-align: middle;
font-size: 24rpx;
}
/* 素材详情 */
.source-detail-page .head {
background-color: #ffffff;
}
.source-detail-page .head image {
display: block;
width: 100%;
height: 420rpx;
object-fit: cover;
pointer-events: none;
}
.source-detail-page .foot {
position: fixed;
bottom: 0;
left: 0;
z-index: 99;
display: flex;
align-items: center;
width: 100%;
height: 100rpx;
padding-right: 35rpx;
padding-left: 50rpx;
border-top: 1px solid #eeeeee;
background-color: #ffffff;
}
.source-detail-page .foot .link {
font-size: 18rpx;
line-height: 25rpx;
text-align: center;
color: #666666;
cursor: pointer;
}
.source-detail-page .foot .link .link {
margin-left: 60rpx;
}
.source-detail-page .foot image {
height: 34rpx;
margin-bottom: 9rpx;
}
.source-detail-page .foot .button {
flex: 1;
min-width: 0;
height: 76rpx;
border-radius: 38rpx;
margin-left: 55rpx;
background: linear-gradient(90deg, #409dff 0%, #1e85fb 100%);
font-size: 28rpx;
line-height: 76rpx;
text-align: center;
color: #ffffff;
cursor: pointer;
}
.source-detail-page .dialog {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1002;
height: 914rpx;
padding: 30rpx 30rpx 130rpx 30rpx;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
background-color: #ffffff;
overflow: auto;
-webkit-overflow-scrolling: touch;
transform: translateY(100%);
transition: transform 0.3s;
}
.source-detail-page .dialog.active {
transform: translateY(0);
}
.source-detail-page .mask {
z-index: 1001;
background-color: rgba(0, 0, 0, 0.5);
}
.source-detail-page .dialog .li+.li {
margin-top: 23rpx;
}
.source-detail-page .dialog navigator {
display: flex;
align-items: center;
}
.source-detail-page .dialog .figure {
position: relative;
}
.source-detail-page .dialog image {
display: block;
width: 250rpx;
height: 140rpx;
border-radius: 10rpx;
object-fit: cover;
pointer-events: none;
-webkit-touch-callout: none;
}
.source-detail-page .dialog .figure text {
position: absolute;
right: 10rpx;
bottom: 10rpx;
width: 66rpx;
height: 34rpx;
border-radius: 3rpx;
background-color: rgba(0, 0, 0, 0.5);
font-size: 22rpx;
line-height: 34rpx;
text-align: center;
color: #ffffff;
}
.source-detail-page .dialog .figcaption {
flex: 1;
min-width: 0;
margin-left: 17rpx;
}
.source-detail-page .dialog .title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 30rpx;
line-height: 42rpx;
color: #333333;
}
.source-detail-page .dialog .mark {
margin-top: 8rpx;
font-size: 0;
}
.source-detail-page .dialog .mark text {
display: inline-block;
height: 40rpx;
padding-right: 10rpx;
padding-left: 10rpx;
border-radius: 10rpx;
background-color: rgba(44, 142, 255, 0.06);
font-size: 20rpx;
line-height: 40rpx;
color: #2c8eff;
}
.source-detail-page .dialog .mark text text {
margin-left: 17rpx;
}
.source-detail-page .dialog .info {
display: flex;
align-items: center;
margin-top: 22rpx;
}
.source-detail-page .dialog .money {
font-weight: bold;
font-size: 24rpx;
color: #ff6b00;
}
.source-detail-page .dialog .money text {
font-size: 32rpx;
line-height: 45rpx;
}
.source-detail-page .dialog .lesson {
flex: 1;
min-height: 0;
margin-left: 9rpx;
font-size: 22rpx;
color: #999999;
}
.source-detail-page .dialog .learn {
font-size: 22rpx;
color: #999999;
}
/* 素材详情 */
.source-detail-page .cover {
display: block;
width: 100%;
object-fit: cover;
pointer-events: none;
-webkit-touch-callout: none;
}
.source-detail-page .title-wrap {
padding-top: 25rpx;
padding-right: 30rpx;
padding-left: 30rpx;
}
.source-detail-page .title-wrap .title {
-webkit-line-clamp: 2;
overflow: hidden;
font-size: 32rpx;
line-height: 50rpx;
color: #333333;
}
.source-detail-page .title-wrap .wrap {
display: flex;
justify-content: space-between;
align-items: flex-end;
padding-top: 18rpx;
padding-bottom: 18rpx;
}
.source-detail-page .title-wrap .learn {
font-size: 22rpx;
line-height: 45rpx;
color: #999999;
}
.source-detail-page .title-wrap .share {
font-size: 26rpx;
line-height: 37rpx;
text-align: center;
color: #999999;
cursor: pointer;
}
.source-detail-page .title-wrap .iconfenxiang {
margin-bottom: 13rpx;
font-size: 40rpx;
color: #707070;
}
.source-detail-page .main {
border-top: 14rpx solid #f5f5f5;
}
.source-detail-page .main .title {
padding-top: 25rpx;
padding-bottom: 26rpx;
padding-left: 28rpx;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.03);
font-weight: bold;
font-size: 32rpx;
line-height: 45rpx;
color: #282828;
}
.source-detail-page .main .wrap {
padding: 30rpx 30rpx 130rpx;
}
.source-detail-page .main .wrap image {
display: block;
width: 100%;
pointer-events: none;
-webkit-touch-callout: none;
}
.source-detail-page .footer {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1001;
display: flex;
align-items: center;
height: 100rpx;
padding-right: 35rpx;
padding-left: 50rpx;
border-top: 1px solid #eeeeee;
background-color: #ffffff;
}
.source-detail-page .footer button {
flex: 1;
height: 76rpx;
border-radius: 38rpx;
margin-left: 55rpx;
background: linear-gradient(90deg, #409dff 0%, #1e85fb 100%);
font-size: 28rpx;
color: #ffffff;
}
.source-detail-page .footer view {
font-size: 20rpx;
line-height: 36rpx;
text-align: center;
color: #666666;
}
.source-detail-page .footer view view {
margin-left: 60rpx;
cursor: pointer;
}
.source-detail-page .footer image {
display: block;
height: 44rpx;
margin: 0 auto;
pointer-events: none;
-webkit-touch-callout: none;
}
.source-detail-page .share-mask {
position: fixed;
top: 0;
left: 0;
z-index: 1003;
width: 100%;
height: 100%;
cursor: pointer;
}
.source-detail-page .progress {
// display: flex;
// align-items: center;
// padding-top: 25rpx;
// padding-right: 30rpx;
// padding-left: 30rpx;
}
.source-detail-page .progress .time {
width: 80rpx;
font-size: 28rpx;
line-height: 40rpx;
color: #2c8eff;
}
.source-detail-page .progress .time:last-child {
text-align: right;
}
.source-detail-page .progress .track {
flex: 1;
height: 4rpx;
border-radius: 2rpx;
margin-right: 16rpx;
margin-left: 16rpx;
background-color: rgba(44, 142, 255, 0.3);
}
.source-detail-page .progress .range {
position: relative;
width: 50%;
height: 100%;
background-color: rgba(44, 142, 255, 0.8);
cursor: pointer;
}
.source-detail-page .progress .thumb {
// position: absolute;
// top: -6rpx;
// right: -6rpx;
// width: 16rpx;
// height: 16rpx;
// border-radius: 50%;
// background-color: #2c8eff;
}
.source-detail-page .handle-wrap {
display: flex;
justify-content: center;
align-items: center;
padding-top: 35rpx;
padding-bottom: 50rpx;
}
.source-detail-page .handle-wrap .iconfont {
font-size: 36rpx;
color: #cccccc;
}
.source-detail-page .handle-wrap button:disabled .iconfont {
color: #46505b;
}
.source-detail-page .handle-wrap button:nth-child(2) {
margin-right: 88rpx;
margin-left: 88rpx;
}
.source-detail-page .handle-wrap svg {
font-size: 110rpx;
}
.source-detail-page .empty {
position: absolute;
top: 50%;
left: 50%;
width: 414rpx;
height: 336rpx;
transform: translate(-50%, -50%);
}
.third {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 54;
display: flex;
align-items: center;
padding-right: 30rpx;
padding-bottom: var(--safe-bottom);
border-top: 1px solid #eeeeee;
background-color: #ffffff;
}
.third .group {
padding: 0 22rpx;
}
.third .group .btn {
height: 100rpx;
padding: 0 28rpx;
font-size: 18rpx;
line-height: 24rpx;
color: #333333;
}
.third .group image {
width: 40rpx;
height: 40rpx;
margin-bottom: 5rpx;
vertical-align: middle;
}
.third .submit-btn {
flex: 1;
height: 76rpx;
border-radius: 38rpx;
background: linear-gradient(90deg, #409dff 0%, #1e85fb 100%);
font-size: 28rpx;
color: #ffffff;
}
.player-self {
width: 100%;
}
.audio-player {
display: flex;
flex-direction: column;
justify-content: center;
}
.audio-player .image {
display: block;
width: 464rpx;
margin: 0 auto;
height: 160rpx;
}
.audio-player .control {
display: flex;
align-items: center;
padding: 40rpx 30rpx 0;
}
.audio-player .icon {
font-size: 64rpx;
color: #2C8EFF;
}
.audio-player .timeline {
flex: 1;
display: flex;
align-items: center;
margin-left: 30rpx;
font-size: 28rpx;
color: #2C8EFF;
}
.audio-player .progress {
flex: 1;
height: 4rpx;
border-radius: 2rpx;
margin: 0 18rpx;
background-color: rgba(44, 142, 255, 0.2);
}
.audio-player .inner {
position: relative;
width: 0;
height: 4rpx;
border-radius: 2rpx;
background-color: #2C8EFF;
}
.audio-player .thumb {
position: absolute;
top: 50%;
right: 0;
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background-color: #2C8EFF;
transform: translate(50%, -50%);
}
.icon {
height: auto !important;
}
</style>