|
|
|
<template>
|
|
|
|
<BaseContainer class="task-info">
|
|
|
|
<NavBar :title="title" />
|
|
|
|
<!-- 视频窗口 -->
|
|
|
|
<view :style="{ height: playerHeight + 'px' }" class="player">
|
|
|
|
<!-- <view :hidden="taskInfo.type == 2" id="J_prismPlayer"></view> -->
|
|
|
|
<image v-if="taskInfo.type == 2" :src="taskInfo.image" />
|
|
|
|
<video id="player" @loadedmetadata="handleVideoLoaded" @timeupdate="onPlayerTimeupdate" @play="play"
|
|
|
|
class="player-self" v-if="taskInfo.type == 3" @ended="onPlayerEnded" :poster="taskInfo.image"
|
|
|
|
:src="taskInfo.link" object-fit="cover"></video>
|
|
|
|
</view>
|
|
|
|
<view class="task-info-body">
|
|
|
|
<view>{{ taskInfo.title }}</view>
|
|
|
|
<view>已播放{{ taskInfo.play_count }}次</view>
|
|
|
|
</view>
|
|
|
|
<!-- 音频播放 -->
|
|
|
|
<view v-if="taskInfo.type == 2" class="audio">
|
|
|
|
|
|
|
|
<view class="control flex flex-center">
|
|
|
|
<view class="iconfont " @click="audioTab(0)">
|
|
|
|
|
|
|
|
<image style="width:44rpx; height:48rpx;" :src=" getImgPath(`/wap/first/zsff/images/c2.png`)" mode="" />
|
|
|
|
|
|
|
|
</view>
|
|
|
|
<view @click="audioPlay" class="play-btn">
|
|
|
|
<i class="iconfont icon" >
|
|
|
|
<image style="width:100rpx; height:100rpx;" :src="audioPaused ?getImgPath(`/wap/first/zsff/images/plays.png`) : getImgPath(`/wap/first/zsff/images/paue.png`)" mode="" />
|
|
|
|
</i>
|
|
|
|
</view>
|
|
|
|
<view class="iconfont " type="button" @click="audioTab(1)">
|
|
|
|
|
|
|
|
<image style="width:44rpx; height:48rpx;" :src="getImgPath(`/wap/first/zsff/images/c1.png`)" mode="" />
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<view class="progress">
|
|
|
|
<view class="time">{{ currentTime | format(duration) }}</view>
|
|
|
|
<view class="bar" @click="audioSeek">
|
|
|
|
<view :style="{ width: audioRange + '%' }" class="range" data-id="range">
|
|
|
|
<view class="dot" data-id="dot" @touchmove="audioMove" @touchend="audioMoveEnd"></view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<view class="time">{{ duration | format }}</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 目录、详情 -->
|
|
|
|
<view class="tabbar">
|
|
|
|
<view :class="{ on: tabIndex == 0 }" @click="tabIndex = 0">目录</view>
|
|
|
|
<view :class="{ on: tabIndex == 1 }" @click="tabIndex = 1">详情</view>
|
|
|
|
</view>
|
|
|
|
<view v-if="tabIndex == 0">
|
|
|
|
<view class="catalogue">
|
|
|
|
<view class="catalogue-item" v-for="(item, index) in taskList" :key="item.id" :class="{ on: item.id == taskId }"
|
|
|
|
@click="playTask(item)">
|
|
|
|
<view>
|
|
|
|
<image v-if="item.type == 1" class="img" :src="getImgPath('/wap/first/zsff/images/media1.png')" />
|
|
|
|
<image v-else-if="item.type == 2" class="img" :src="getImgPath('/wap/first/zsff/images/media2.png')" />
|
|
|
|
<image v-else-if="item.type == 3" class="img" :src="getImgPath('/wap/first/zsff/images/media3.png')" />
|
|
|
|
</view>
|
|
|
|
<view class="text">
|
|
|
|
<view class="title">
|
|
|
|
{{ index >= 9 ? index + 1 : "0" + (index + 1) }} | {{ item.title }}
|
|
|
|
</view>
|
|
|
|
<view class="try-progress">
|
|
|
|
<view v-if="item.watch && item.watch.percentage" class="progress">
|
|
|
|
已学习{{ item.watch.percentage }}%
|
|
|
|
</view>
|
|
|
|
<view v-else class="progress no">未学习</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<view class="status">
|
|
|
|
<i v-if="item.is_free" :class="[item.pay_status ? 'iconsuozi' : 'iconziyuan2', 'iconfont']"></i>
|
|
|
|
<span v-else class="free">免费</span>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<view v-else-if="tabIndex == 1" style="background: #fff;">
|
|
|
|
<mp-html class="content" container-style="padding: 30rpx; background: #ffffff;"
|
|
|
|
:content="taskInfo.content"></mp-html>
|
|
|
|
</view>
|
|
|
|
</BaseContainer>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import {
|
|
|
|
getCourseList,
|
|
|
|
getTaskInfo,
|
|
|
|
getVideoPlayCredentials,
|
|
|
|
getVideoPlayDuration,
|
|
|
|
saveSpecialViewing,
|
|
|
|
} from "@/api/special";
|
|
|
|
import dayjs from "dayjs";
|
|
|
|
import mpHtml from "mp-html/dist/uni-app/components/mp-html/mp-html.vue";
|
|
|
|
|
|
|
|
export default {
|
|
|
|
components: {
|
|
|
|
mpHtml,
|
|
|
|
},
|
|
|
|
filters: {
|
|
|
|
format(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");
|
|
|
|
},
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
title() {
|
|
|
|
if (!this.taskInfo.id) return " ";
|
|
|
|
return this.taskInfo.type === 2 ? "音频素材" : "视频素材";
|
|
|
|
},
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
try_num: 0,
|
|
|
|
taskId: 0,
|
|
|
|
specialId: 0,
|
|
|
|
playerHeight: 0,
|
|
|
|
taskInfo: {
|
|
|
|
play_count: 0,
|
|
|
|
},
|
|
|
|
taskList: [],
|
|
|
|
tabIndex: 0,
|
|
|
|
duration: 0,
|
|
|
|
currentTime: 0,
|
|
|
|
audioRange: 0,
|
|
|
|
audioPaused: true,
|
|
|
|
page: 1,
|
|
|
|
limit: 10,
|
|
|
|
loading: false,
|
|
|
|
finished: false,
|
|
|
|
player: null,
|
|
|
|
viewing_time: 0,
|
|
|
|
isPay: false,
|
|
|
|
player: null,
|
|
|
|
videoContext: null,
|
|
|
|
audioBarPos: {
|
|
|
|
width: 0,
|
|
|
|
left: 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
},
|
|
|
|
onLoad({ id, specialId, viewing_time = 0 }) {
|
|
|
|
this.taskId = id;
|
|
|
|
this.specialId = specialId;
|
|
|
|
this.viewing_time = viewing_time / 1e3;
|
|
|
|
this.currentTime = Math.floor(this.viewing_time);
|
|
|
|
console.log(this.viewing_time)
|
|
|
|
const { screenWidth } = this.$util.getSystemInfo();
|
|
|
|
this.playerHeight = Math.floor((screenWidth * 9) / 16);
|
|
|
|
this.getTaskList();
|
|
|
|
|
|
|
|
},
|
|
|
|
onReachBottom() {
|
|
|
|
this.getTaskList();
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.getTaskInfo().then(() => {
|
|
|
|
this.taskInfo.type === 2 &&
|
|
|
|
this.$util.getClientRect(".bar").then(({ width, left }) => {
|
|
|
|
this.audioBarPos.width = width;
|
|
|
|
this.audioBarPos.left = left;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
play() {
|
|
|
|
// #ifdef APP-PLUS
|
|
|
|
this.player.seek(parseInt(this.currentTime));
|
|
|
|
// #endif
|
|
|
|
},
|
|
|
|
// 获取播放信息
|
|
|
|
getTaskInfo() {
|
|
|
|
return getTaskInfo(this.specialId, this.taskId).then(({ data }) => {
|
|
|
|
this.isPay = data.isPay;
|
|
|
|
this.specialInfo = data.specialInfo;
|
|
|
|
this.taskInfo = data.taskInfo;
|
|
|
|
/* if (this.taskInfo.videoId) {
|
|
|
|
this.getPlayAuth();
|
|
|
|
} else */ if (this.taskInfo.type === 3) {
|
|
|
|
this.createPlayer();
|
|
|
|
} else {
|
|
|
|
this.createAudioPlayer();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
createAudioPlayer() {
|
|
|
|
if (this.player) {
|
|
|
|
this.player.stop();
|
|
|
|
this.player = null;
|
|
|
|
this.audioPaused = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const innerAudioContext = uni.createInnerAudioContext();
|
|
|
|
innerAudioContext.autoplay = false;
|
|
|
|
innerAudioContext.src = this.taskInfo.link;
|
|
|
|
|
|
|
|
innerAudioContext.onCanplay(() => {
|
|
|
|
let intervalID = setInterval(() => {
|
|
|
|
if (innerAudioContext.duration !== 0) {
|
|
|
|
clearInterval(intervalID);
|
|
|
|
this.duration = innerAudioContext.duration;
|
|
|
|
// #ifdef APP
|
|
|
|
this.player.seek(this.viewing_time);
|
|
|
|
//#endif
|
|
|
|
this.audioRange = Math.floor((this.viewing_time / this.duration) * 100)
|
|
|
|
}
|
|
|
|
}, 100);
|
|
|
|
});
|
|
|
|
|
|
|
|
innerAudioContext.onEnded(() => {
|
|
|
|
this.onPlayerEnded();
|
|
|
|
});
|
|
|
|
|
|
|
|
innerAudioContext.onTimeUpdate(() => {
|
|
|
|
this.onPlayerTimeupdate();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.player = innerAudioContext;
|
|
|
|
if (this.viewing_time) {
|
|
|
|
this.player.seek(this.viewing_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
onUnload() {
|
|
|
|
if (!this.player) return;
|
|
|
|
this.player.pause()
|
|
|
|
},
|
|
|
|
// 获取palyauth
|
|
|
|
getPlayAuth() {
|
|
|
|
getVideoPlayCredentials(this.taskInfo.videoId, 2).then(({ msg }) => {
|
|
|
|
getVideoPlayDuration(msg).then((res) => {
|
|
|
|
try {
|
|
|
|
var data = JSON.parse(res.responseText);
|
|
|
|
if (request.status === 200) {
|
|
|
|
this.duration = data.VideoMeta.Duration;
|
|
|
|
this.createPlayer(data.PlayAuth);
|
|
|
|
} else {
|
|
|
|
this.$util.showMsg(data.Message);
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
this.$util.showMsg(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 创建播放器
|
|
|
|
createPlayer(playauth) {
|
|
|
|
if (this.player) {
|
|
|
|
this.player.stop();
|
|
|
|
this.player = null;
|
|
|
|
}
|
|
|
|
this.player = uni.createVideoContext("player");
|
|
|
|
},
|
|
|
|
|
|
|
|
// 初始播放位置
|
|
|
|
handleVideoLoaded(e) {
|
|
|
|
this.duration = e.target.duration;
|
|
|
|
if (!this.isPay && this.taskInfo.is_try) {
|
|
|
|
// this.player.seek(this.taskInfo.try_time * 60);
|
|
|
|
} else {
|
|
|
|
this.player.seek(this.viewing_time);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onPlayerTimeupdate(e) {
|
|
|
|
if (this.duration == 0 && this.taskInfo.type == 3) {
|
|
|
|
this.duration = e.target.duration;
|
|
|
|
}
|
|
|
|
if (parseInt(this.currentTime) == parseInt(this.duration)) {
|
|
|
|
this.player.seek(0);
|
|
|
|
}
|
|
|
|
this.currentTime = this.taskInfo.type == 3 ? e.detail.currentTime : this.player.currentTime;
|
|
|
|
this.audioRange = Math.floor((this.currentTime / this.duration) * 100);
|
|
|
|
if (!this.isPay) {
|
|
|
|
if (this.taskInfo.is_try && this.currentTime >= this.taskInfo.try_time * 60) {
|
|
|
|
this.audioPaused = true;
|
|
|
|
this.player.pause()
|
|
|
|
this.player.seek(0)
|
|
|
|
this.onPlayerEnded();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// this.player.seek(parseInt(this.currentTime));
|
|
|
|
// this.player.seek(this.currentTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
var floorTime = Math.floor(this.currentTime);
|
|
|
|
if (floorTime && floorTime != this.floorTime && !(floorTime % 10)) {
|
|
|
|
this.floorTime = floorTime;
|
|
|
|
this.setViewing(this.currentTime);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// 播放结束
|
|
|
|
onPlayerEnded() {
|
|
|
|
|
|
|
|
if (!this.isPay) {
|
|
|
|
this.currentTime = 0
|
|
|
|
uni.showModal({
|
|
|
|
title: "提示",
|
|
|
|
content: "购买后可看全部内容,是否购买?",
|
|
|
|
confirmText: "购买",
|
|
|
|
success: ({ confirm }) => {
|
|
|
|
if (!confirm) return;
|
|
|
|
uni.navigateBack({})
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.setViewing(this.duration);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// 获取专栏列表
|
|
|
|
getTaskList() {
|
|
|
|
if (this.finished) return;
|
|
|
|
getCourseList({
|
|
|
|
special_id: this.specialId,
|
|
|
|
page: this.page,
|
|
|
|
limit: this.limit,
|
|
|
|
}).then(({ data }) => {
|
|
|
|
let list = Array.isArray(data) ? [] : data.list;
|
|
|
|
this.taskList = this.taskList.concat(list);
|
|
|
|
this.finished = this.limit > list.length;
|
|
|
|
if (!this.finished) {
|
|
|
|
this.page++;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 点击目录
|
|
|
|
playTask(item) {
|
|
|
|
if (item.id == this.taskId) return;
|
|
|
|
if (item.pay_status && !this.isPay && this.specialInfo.pay_type) {
|
|
|
|
this.$util.showMsg("请先去购买");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.taskId = item.id;
|
|
|
|
this.viewing_time = (item.watch && item.watch.viewing_time / 1e3) || 0;
|
|
|
|
this.currentTime = Math.floor(this.viewing_time);
|
|
|
|
this.seeked = false;
|
|
|
|
this.getTaskInfo();
|
|
|
|
},
|
|
|
|
// 更新播放进度
|
|
|
|
setViewing(currentTime) {
|
|
|
|
saveSpecialViewing({
|
|
|
|
special_id: this.specialId,
|
|
|
|
task_id: this.taskId,
|
|
|
|
total: this.duration * 1e3,
|
|
|
|
viewing_time: currentTime * 1e3,
|
|
|
|
percentage: Math.floor((currentTime / this.duration) * 100),
|
|
|
|
}).then(res => {
|
|
|
|
console.log(res)
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 播放/暂停音频
|
|
|
|
audioPlay() {
|
|
|
|
if (this.player) {
|
|
|
|
this.audioPaused = !this.audioPaused;
|
|
|
|
this.audioPaused ? this.player.pause() : this.player.play();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// 设置音频进度
|
|
|
|
setAudioRange() {
|
|
|
|
this.audioRange = Math.floor((this.currentTime / this.duration) * 100);
|
|
|
|
},
|
|
|
|
// 跳到音频的新位置
|
|
|
|
audioSeek(event) {
|
|
|
|
const barWidth = this.audioBarPos.width;
|
|
|
|
const barLeft = this.audioBarPos.left;
|
|
|
|
|
|
|
|
const range = (event.touches[0].pageX - barLeft) / barWidth;
|
|
|
|
this.audioRange = range * 100;
|
|
|
|
this.currentTime = this.duration * range;
|
|
|
|
this.player.seek(this.currentTime);
|
|
|
|
},
|
|
|
|
// 上一个音频/下一个音频
|
|
|
|
audioTab(state) {
|
|
|
|
if (!this.player) return;
|
|
|
|
if (!this.player.paused) {
|
|
|
|
this.audioPaused = true;
|
|
|
|
this.player.pause();
|
|
|
|
}
|
|
|
|
let index = 0;
|
|
|
|
for (let i = this.taskList.length; i--;) {
|
|
|
|
if (this.taskList[i].id === this.taskId) {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (index === this.taskList.length - 1 && state) {
|
|
|
|
return this.$util.showMsg("已经是最后一个");
|
|
|
|
}
|
|
|
|
if (!index && !state) {
|
|
|
|
return this.$util.showMsg("已经是第一个");
|
|
|
|
}
|
|
|
|
let task = state ? this.taskList[index + 1] : this.taskList[index - 1];
|
|
|
|
if (task.pay_status) {
|
|
|
|
return this.$util.showMsg("请先去购买");
|
|
|
|
}
|
|
|
|
this.playTask(task);
|
|
|
|
},
|
|
|
|
// 滑动音频
|
|
|
|
audioMove(event) {
|
|
|
|
if (!this.player || !this.player.paused) {
|
|
|
|
this.audioPaused = true;
|
|
|
|
this.player.pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$util.getClientRect(".bar").then(({ left, width }) => {
|
|
|
|
let range = Math.floor(((event.touches[0].pageX - left) / width) * 100);
|
|
|
|
if (range > 100) {
|
|
|
|
range = 100;
|
|
|
|
}
|
|
|
|
this.audioRange = range;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 滑动音频停止
|
|
|
|
audioMoveEnd() {
|
|
|
|
if (!this.player) return;
|
|
|
|
this.player.seek((this.duration * this.audioRange) / 100);
|
|
|
|
if (this.player.paused) {
|
|
|
|
this.audioPaused = false;
|
|
|
|
this.player.play();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
page{
|
|
|
|
background: #F7F8F9;
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.task-info .tabbar {
|
|
|
|
display: flex;
|
|
|
|
border-top: 16rpx solid #f5f5f5;
|
|
|
|
background: #ffffff;
|
|
|
|
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.03);
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .tabbar view {
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
flex: 1;
|
|
|
|
height: 96rpx;
|
|
|
|
font-size: 30rpx;
|
|
|
|
line-height: 96rpx;
|
|
|
|
text-align: center;
|
|
|
|
color: #333;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .tabbar view.on {
|
|
|
|
font-weight: 500;
|
|
|
|
font-size: 32rpx;
|
|
|
|
color: #2c8eff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .tabbar view.on::after {
|
|
|
|
content: " ";
|
|
|
|
position: absolute;
|
|
|
|
bottom: 15rpx;
|
|
|
|
left: 50%;
|
|
|
|
width: 30rpx;
|
|
|
|
height: 8rpx;
|
|
|
|
border-radius: 10rpx;
|
|
|
|
background-color: #2c8eff;
|
|
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
}
|
|
|
|
.catalogue{
|
|
|
|
background: #ffffff;
|
|
|
|
}
|
|
|
|
.catalogue .catalogue-item.on{
|
|
|
|
background: #ffffff !important;
|
|
|
|
.text{
|
|
|
|
.title{
|
|
|
|
color: #1D8DFF ;
|
|
|
|
font-size: 30rpx;
|
|
|
|
font-weight: 500;
|
|
|
|
color: #1D8DFF;
|
|
|
|
line-height: 48rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.task-info .prism-player .prism-big-play-btn {
|
|
|
|
left: 50% !important;
|
|
|
|
bottom: 50% !important;
|
|
|
|
|
|
|
|
transform: translate(-50%, 50%);
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .player>image {
|
|
|
|
display: block;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
object-fit: cover;
|
|
|
|
-webkit-touch-callout: none;
|
|
|
|
pointer-events: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .content {
|
|
|
|
background-color: #ffffff;
|
|
|
|
font-size: 30rpx;
|
|
|
|
line-height: 44rpx;
|
|
|
|
color: #333;
|
|
|
|
word-break: break-all;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .content image {
|
|
|
|
display: block;
|
|
|
|
width: 100%;
|
|
|
|
pointer-events: none;
|
|
|
|
-webkit-touch-callout: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .catalogue-item {
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
height: 152rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .catalogue-item::before {
|
|
|
|
content: "";
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
right: 0;
|
|
|
|
left: 91rpx;
|
|
|
|
border-top: 1px solid #f5f5f5;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .catalogue-item:first-child::before {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .catalogue-item.on {
|
|
|
|
background-color: #f9fafc;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue image {
|
|
|
|
display: block;
|
|
|
|
width: 38rpx;
|
|
|
|
height: 27rpx;
|
|
|
|
margin: 0 33rpx 0 20rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .text {
|
|
|
|
flex: 1;
|
|
|
|
min-width: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .title {
|
|
|
|
overflow: hidden;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
font-size: 28rpx;
|
|
|
|
line-height: 40rpx;
|
|
|
|
color: #333333;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .try-progress {
|
|
|
|
margin-top: 15rpx;
|
|
|
|
font-size: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .try,
|
|
|
|
.task-info .catalogue .progress {
|
|
|
|
display: inline-block;
|
|
|
|
padding: 2.5rpx 7rpx;
|
|
|
|
border: 1px solid transparent;
|
|
|
|
border-radius: 3rpx;
|
|
|
|
font-size: 18rpx;
|
|
|
|
line-height: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .try {
|
|
|
|
border-color: #2c8eff;
|
|
|
|
color: #2c8eff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .progress {
|
|
|
|
padding-left: 9rpx;
|
|
|
|
border-color: #fff0e5;
|
|
|
|
background-color: #fff0e5;
|
|
|
|
color: #ff6b00;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .progress.no {
|
|
|
|
border-color: #dddddd;
|
|
|
|
background-color: #dddddd;
|
|
|
|
color: #999999;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .try+.progress {
|
|
|
|
margin-left: 15rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .status {
|
|
|
|
width: 130rpx;
|
|
|
|
font-size: 0;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .free {
|
|
|
|
display: inline-block;
|
|
|
|
width: 90rpx;
|
|
|
|
height: 40rpx;
|
|
|
|
border-radius: 20rpx;
|
|
|
|
background-color: #fff0e5;
|
|
|
|
font-size: 22rpx;
|
|
|
|
line-height: 40rpx;
|
|
|
|
text-align: center;
|
|
|
|
color: #ff6b00;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .catalogue .iconfont {
|
|
|
|
font-size: 34rpx;
|
|
|
|
color: #cccccc;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info-body {
|
|
|
|
padding: 30rpx;
|
|
|
|
background-color: #ffffff;
|
|
|
|
font-size: 24rpx;
|
|
|
|
color: #999999;
|
|
|
|
border-radius: 32rpx 32rpx 0rpx 0rpx;
|
|
|
|
position: relative;
|
|
|
|
margin-top: -20rpx;
|
|
|
|
z-index: 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info-body view:first-child {
|
|
|
|
margin-bottom: 10rpx;
|
|
|
|
font-size: 36rpx;
|
|
|
|
color: #333;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .audio {
|
|
|
|
padding-bottom: 49rpx;
|
|
|
|
background: #ffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .audio .progress {
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
margin-right: 30rpx;
|
|
|
|
margin-left: 30rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .audio .progress .time {
|
|
|
|
width: 75rpx;
|
|
|
|
font-size: 28rpx;
|
|
|
|
color: #2c8eff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .audio .progress .bar {
|
|
|
|
flex: 1;
|
|
|
|
border-radius: 2rpx;
|
|
|
|
background-color: rgba(44, 142, 255, 0.3);
|
|
|
|
margin-right: 18rpx;
|
|
|
|
margin-left: 18rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .audio .progress .range {
|
|
|
|
position: relative;
|
|
|
|
height: 4rpx;
|
|
|
|
border-radius: 2rpx;
|
|
|
|
background-color: rgba(44, 142, 255, 0.8);
|
|
|
|
|
|
|
|
transition: 0.2s linear;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .audio .progress .dot {
|
|
|
|
position: absolute;
|
|
|
|
top: 50%;
|
|
|
|
left: 100%;
|
|
|
|
width: 16rpx;
|
|
|
|
height: 16rpx;
|
|
|
|
border-radius: 50%;
|
|
|
|
background-color: #2c8eff;
|
|
|
|
|
|
|
|
transform: translate(-50%, -50%);
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .control {
|
|
|
|
margin-top: 34rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .control .iconfont {
|
|
|
|
font-size: 36rpx;
|
|
|
|
color: #46505b;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .control .play-btn {
|
|
|
|
margin-right: 88rpx;
|
|
|
|
margin-left: 88rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.task-info .control .icon {
|
|
|
|
font-size: 110rpx;
|
|
|
|
color: #2c8eff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.player-self {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
/* #ifdef MP-WEIXIN */
|
|
|
|
height: auto !important;
|
|
|
|
/* #endif */
|
|
|
|
}
|
|
|
|
</style>
|